From 0934450b518be6bc7fb8208935195809dc9ca3a1 Mon Sep 17 00:00:00 2001 From: Jillian Date: Mon, 9 Oct 2023 11:06:19 +1030 Subject: [PATCH] Adds missing __init__.py files [FC-0030] (#90) chore: adds missing __init__.py files and fixes resulting pylint issues * fixes a number of translation-of-non-string * fixes coverage for files in tests/ * fixes PytestCollectionWarnings --- openedx_tagging/core/__init__.py | 0 openedx_tagging/core/tagging/api.py | 8 +-- .../core/tagging/import_export/__init__.py | 3 ++ .../core/tagging/import_export/actions.py | 38 +++++++------- .../core/tagging/import_export/api.py | 15 +++--- .../core/tagging/import_export/exceptions.py | 51 ++++++++++--------- .../core/tagging/import_export/parsers.py | 10 ++-- .../core/tagging/models/import_export.py | 40 +++++++++++++++ .../core/tagging/rest_api/__init__.py | 0 .../core/tagging/rest_api/paginators.py | 4 ++ .../core/tagging/rest_api/v1/permissions.py | 15 ++++++ .../core/tagging/rest_api/v1/serializers.py | 27 ++++++++-- .../core/tagging/rest_api/v1/views.py | 10 ++-- .../openedx_tagging/core/tagging/test_api.py | 27 ++-------- .../core/tagging/test_models.py | 14 ++--- .../tagging/test_system_defined_models.py | 8 +-- .../core/tagging/test_views.py | 3 +- 17 files changed, 172 insertions(+), 101 deletions(-) create mode 100644 openedx_tagging/core/__init__.py create mode 100644 openedx_tagging/core/tagging/rest_api/__init__.py diff --git a/openedx_tagging/core/__init__.py b/openedx_tagging/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/openedx_tagging/core/tagging/api.py b/openedx_tagging/core/tagging/api.py index f8106590..e9140968 100644 --- a/openedx_tagging/core/tagging/api.py +++ b/openedx_tagging/core/tagging/api.py @@ -14,7 +14,7 @@ from django.db import transaction from django.db.models import F, QuerySet -from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext as _ from .models import ObjectTag, Tag, Taxonomy @@ -196,11 +196,11 @@ def _check_new_tag_count(new_tag_count: int) -> None: if current_count + new_tag_count > 100: raise ValueError( - _(f"Cannot add more than 100 tags to ({object_id}).") + _("Cannot add more than 100 tags to ({object_id}).").format(object_id=object_id) ) if not isinstance(tags, list): - raise ValueError(_(f"Tags must be a list, not {type(tags).__name__}.")) + raise ValueError(_("Tags must be a list, not {type}.").format(type=type(tags).__name__)) ObjectTagClass = object_tag_class taxonomy = taxonomy.cast() # Make sure we're using the right subclass. This is a no-op if we are already. @@ -209,7 +209,7 @@ def _check_new_tag_count(new_tag_count: int) -> None: _check_new_tag_count(len(tags)) if not taxonomy.allow_multiple and len(tags) > 1: - raise ValueError(_(f"Taxonomy ({taxonomy.name}) only allows one tag per object.")) + raise ValueError(_("Taxonomy ({name}) only allows one tag per object.").format(name=taxonomy.name)) current_tags = list( ObjectTagClass.objects.filter(taxonomy=taxonomy, object_id=object_id) diff --git a/openedx_tagging/core/tagging/import_export/__init__.py b/openedx_tagging/core/tagging/import_export/__init__.py index 55bcdaeb..fb1088d4 100644 --- a/openedx_tagging/core/tagging/import_export/__init__.py +++ b/openedx_tagging/core/tagging/import_export/__init__.py @@ -1 +1,4 @@ +""" +Externally-facing import/export classes. +""" from .parsers import ParserFormat diff --git a/openedx_tagging/core/tagging/import_export/actions.py b/openedx_tagging/core/tagging/import_export/actions.py index 40919427..b968a6b0 100644 --- a/openedx_tagging/core/tagging/import_export/actions.py +++ b/openedx_tagging/core/tagging/import_export/actions.py @@ -41,7 +41,7 @@ def __init__(self, taxonomy: Taxonomy, tag, index: int): self.index = index def __repr__(self) -> str: - return str(_(f"Action {self.name} (index={self.index},id={self.tag.id})")) + return str(_("Action {name} (index={index},id={id})").format(name=self.name, index=self.index, id=self.tag.id)) def __str__(self) -> str: return self.__repr__() @@ -104,11 +104,10 @@ def _validate_parent(self, indexed_actions) -> ImportActionError | None: ): return ImportActionError( action=self, - tag_id=self.tag.id, message=_( - f"Unknown parent tag ({self.tag.parent_id}). " + "Unknown parent tag ({parent_id}). " "You need to add parent before the child in your file." - ), + ).format(parent_id=self.tag.parent_id), ) return None @@ -122,10 +121,9 @@ def _validate_value(self, indexed_actions) -> ImportActionError | None: taxonomy_tag = self.taxonomy.tag_set.get(value=self.tag.value) return ImportActionError( action=self, - tag_id=self.tag.id, message=_( - f"Duplicated tag value with tag in database (external_id={taxonomy_tag.external_id})." - ), + "Duplicated tag value with tag in database (external_id={external_id})." + ).format(external_id=taxonomy_tag.external_id) ) except Tag.DoesNotExist: # Validates value duplication on create actions @@ -148,7 +146,6 @@ def _validate_value(self, indexed_actions) -> ImportActionError | None: if action: return ImportActionConflict( action=self, - tag_id=self.tag.id, conflict_action_index=action.index, message=_("Duplicated tag value."), ) @@ -175,9 +172,9 @@ def __str__(self) -> str: return str( _( "Create a new tag with values " - f"(external_id={self.tag.id}, value={self.tag.value}, " - f"parent_id={self.tag.parent_id})." - ) + "(external_id={external_id}, value={value}, " + "parent_id={parent_id})." + ).format(external_id=self.tag.id, value=self.tag.value, parent_id=self.tag.parent_id) ) @classmethod @@ -199,7 +196,6 @@ def _validate_id(self, indexed_actions) -> ImportActionError | None: if action: return ImportActionConflict( action=self, - tag_id=self.tag.id, conflict_action_index=action.index, message=_("Duplicated external_id tag."), ) @@ -263,13 +259,13 @@ def __str__(self) -> str: if not taxonomy_tag.parent: from_str = _("from empty parent") else: - from_str = _(f"from parent (external_id={taxonomy_tag.parent.external_id})") + from_str = _("from parent (external_id={external_id})").format(external_id=taxonomy_tag.parent.external_id) return str( _( - f"Update the parent of tag (external_id={taxonomy_tag.external_id}) " - f"{from_str} to parent (external_id={self.tag.parent_id})." - ) + "Update the parent of tag (external_id={external_id}) " + "{from_str} to parent (external_id={parent_id})." + ).format(external_id=taxonomy_tag.external_id, from_str=from_str, parent_id=self.tag.parent_id) ) @classmethod @@ -329,9 +325,9 @@ def __str__(self) -> str: taxonomy_tag = self._get_tag() return str( _( - f"Rename tag value of tag (external_id={taxonomy_tag.external_id}) " - f"from '{taxonomy_tag.value}' to '{self.tag.value}'" - ) + "Rename tag value of tag (external_id={external_id}) " + "from '{from_value}' to '{to_value}'" + ).format(external_id=taxonomy_tag.external_id, from_value=taxonomy_tag.value, to_value=self.tag.value) ) @classmethod @@ -378,7 +374,7 @@ class DeleteTag(ImportAction): def __str__(self) -> str: taxonomy_tag = self._get_tag() - return str(_(f"Delete tag (external_id={taxonomy_tag.external_id})")) + return str(_("Delete tag (external_id={external_id})").format(external_id=taxonomy_tag.external_id)) name = "delete" @@ -415,7 +411,7 @@ class WithoutChanges(ImportAction): name = "without_changes" def __str__(self) -> str: - return str(_(f"No changes needed for tag (external_id={self.tag.id})")) + return str(_("No changes needed for tag (external_id={external_id})").format(external_id=self.tag.id)) @classmethod def applies_for(cls, taxonomy: Taxonomy, tag) -> bool: diff --git a/openedx_tagging/core/tagging/import_export/api.py b/openedx_tagging/core/tagging/import_export/api.py index 77203bf5..c90a78f4 100644 --- a/openedx_tagging/core/tagging/import_export/api.py +++ b/openedx_tagging/core/tagging/import_export/api.py @@ -46,9 +46,10 @@ from io import BytesIO -from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext as _ from ..models import TagImportTask, TagImportTaskState, Taxonomy +from .exceptions import TagImportError from .import_plan import TagImportPlan, TagImportTask from .parsers import ParserFormat, get_parser @@ -115,7 +116,7 @@ def import_tags( tag_import_plan.execute(task) task.end_success() return True - except Exception as exception: + except (TagImportError, ValueError) as exception: # Log any exception task.log_exception(exception) return False @@ -159,8 +160,10 @@ def _check_unique_import_task(taxonomy: Taxonomy) -> bool: if not last_task: return True return ( - last_task.status == TagImportTaskState.SUCCESS.value - or last_task.status == TagImportTaskState.ERROR.value + last_task.status in { + TagImportTaskState.SUCCESS.value, + TagImportTaskState.ERROR.value + } ) @@ -189,6 +192,6 @@ def _import_export_validations(taxonomy: Taxonomy): if taxonomy.system_defined: raise ValueError( _( - f"Invalid taxonomy ({taxonomy.id}): You cannot import/export a system-defined taxonomy." - ) + "Invalid taxonomy ({id}): You cannot import/export a system-defined taxonomy." + ).format(id=taxonomy.id) ) diff --git a/openedx_tagging/core/tagging/import_export/exceptions.py b/openedx_tagging/core/tagging/import_export/exceptions.py index 91a6b6f9..5ec52cad 100644 --- a/openedx_tagging/core/tagging/import_export/exceptions.py +++ b/openedx_tagging/core/tagging/import_export/exceptions.py @@ -16,9 +16,9 @@ class TagImportError(Exception): Base exception for import """ - def __init__(self, message: str = "", **kargs): + def __init__(self, message: str = ""): + super().__init__() self.message = message - super().__init__(message, **kargs) def __str__(self): return str(self.message) @@ -32,10 +32,9 @@ class TagParserError(TagImportError): Base exception for parsers """ - def __init__(self, tag: dict | None, **kargs): + def __init__(self, tag: dict | None, **kargs): # pylint: disable=unused-argument super().__init__() - self.tag = tag - self.message = _(f"Import parser error on {tag}") + self.message = _("Import parser error on {tag}").format(tag=tag) class ImportActionError(TagImportError): @@ -43,10 +42,11 @@ class ImportActionError(TagImportError): Base exception for actions """ - def __init__(self, action: ImportAction, tag_id: str, message: str, **kargs): + def __init__(self, action: ImportAction, message: str, **kargs): + super().__init__(**kargs) self.message = _( - f"Action error in '{action.name}' (#{action.index}): {message}" - ) + "Action error in '{name}' (#{index}): {message}" + ).format(name=action.name, index=action.index, message=message) class ImportActionConflict(ImportActionError): @@ -57,14 +57,19 @@ class ImportActionConflict(ImportActionError): def __init__( self, action: ImportAction, - tag_id: str, conflict_action_index: int, message: str, **kargs, ): + super().__init__(action, message, **kargs) self.message = _( - f"Conflict with '{action.name}' (#{action.index}) " - f"and action #{conflict_action_index}: {message}" + "Conflict with '{action_name}' (#{action_index}) " + "and action #{conflict_action_index}: {message}" + ).format( + action_name=action.name, + action_index=action.index, + conflict_action_index=conflict_action_index, + message=message, ) @@ -73,9 +78,9 @@ class InvalidFormat(TagParserError): Exception used when there is an error with the format """ - def __init__(self, tag: dict | None, format: str, message: str, **kargs): - super().__init__(tag) - self.message = _(f"Invalid '{format}' format: {message}") + def __init__(self, tag: dict | None, input_format: str, message: str, **kargs): + super().__init__(tag, **kargs) + self.message = _("Invalid '{format}' format: {message}").format(format=input_format, message=message) class FieldJSONError(TagParserError): @@ -83,9 +88,9 @@ class FieldJSONError(TagParserError): Exception used when missing a required field on the .json """ - def __init__(self, tag: dict | None, field, **kargs): - super().__init__(tag) - self.message = _(f"Missing '{field}' field on {tag}") + def __init__(self, tag: dict | None, field: str, **kargs): + super().__init__(tag, **kargs) + self.message = _("Missing '{field}' field on {tag}").format(field=field, tag=tag) class EmptyJSONField(TagParserError): @@ -93,9 +98,9 @@ class EmptyJSONField(TagParserError): Exception used when a required field is empty on the .json """ - def __init__(self, tag, field, **kargs): - self.tag = tag - self.message = _(f"Empty '{field}' field on {tag}") + def __init__(self, tag: dict | None, field: str, **kargs): + super().__init__(tag, **kargs) + self.message = _("Empty '{field}' field on {tag}").format(field=field, tag=tag) class EmptyCSVField(TagParserError): @@ -103,6 +108,6 @@ class EmptyCSVField(TagParserError): Exception used when a required field is empty on the .csv """ - def __init__(self, tag, field, row, **kargs): - self.tag = tag - self.message = _(f"Empty '{field}' field on the row {row}") + def __init__(self, tag: dict | None, field: str, row: int, **kargs): + super().__init__(tag, **kargs) + self.message = _("Empty '{field}' field on the row {row}").format(field=field, row=row) diff --git a/openedx_tagging/core/tagging/import_export/parsers.py b/openedx_tagging/core/tagging/import_export/parsers.py index b0132f3d..4413c04c 100644 --- a/openedx_tagging/core/tagging/import_export/parsers.py +++ b/openedx_tagging/core/tagging/import_export/parsers.py @@ -212,13 +212,13 @@ def _load_data(cls, file: BytesIO) -> tuple[list[dict], list[TagParserError]]: tags_data = json.load(file) except json.JSONDecodeError as error: return [], [ - InvalidFormat(tag=None, format=cls.format.value, message=str(error)) + InvalidFormat(tag=None, input_format=cls.format.value, message=str(error)) ] if "tags" not in tags_data: return [], [ InvalidFormat( tag=None, - format=cls.format.value, + input_format=cls.format.value, message=_("Missing 'tags' field on the .json file"), ) ] @@ -298,8 +298,8 @@ def _verify_header(cls, header_fields: list[str]) -> list[TagParserError]: errors.append( InvalidFormat( tag=None, - format=cls.format.value, - message=_(f"Missing '{req_field}' field on CSV headers"), + input_format=cls.format.value, + message=_("Missing '{req_field}' field on CSV headers").format(req_field=req_field), ) ) return errors @@ -319,4 +319,4 @@ def get_parser(parser_format: ParserFormat) -> type[Parser]: if parser_format == parser.format: return parser - raise ValueError(_(f"Parser not found for format {parser_format}")) + raise ValueError(_("Parser not found for format {parser_format}").format(parser_format=parser_format)) diff --git a/openedx_tagging/core/tagging/models/import_export.py b/openedx_tagging/core/tagging/models/import_export.py index c1b41b36..531a4cca 100644 --- a/openedx_tagging/core/tagging/models/import_export.py +++ b/openedx_tagging/core/tagging/models/import_export.py @@ -1,3 +1,7 @@ +""" +Models used by the Taxonomy import/export tasks. +""" + from datetime import datetime from enum import Enum @@ -9,6 +13,9 @@ class TagImportTaskState(Enum): + """ + Enumerates the states that a TagImportTask can be in. + """ LOADING_DATA = "loading_data" PLANNING = "planning" EXECUTING = "executing" @@ -48,6 +55,9 @@ class Meta: @classmethod def create(cls, taxonomy: Taxonomy): + """ + Creates and logs a new TagImportTask. + """ task = cls( taxonomy=taxonomy, status=TagImportTaskState.LOADING_DATA.value, @@ -58,6 +68,9 @@ def create(cls, taxonomy: Taxonomy): return task def add_log(self, message: str, save=True): + """ + Appends a log message to the task. + """ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_message = f"[{timestamp}] {message}\n" self.log += log_message @@ -65,44 +78,71 @@ def add_log(self, message: str, save=True): self.save() def log_exception(self, exception: Exception): + """ + Logs an exception and moves the task status to ERROR. + """ self.add_log(repr(exception), save=False) self.status = TagImportTaskState.ERROR.value self.save() def log_parser_start(self): + """ + Logs the parser start event. + """ self.add_log(_("Starting to load data from file")) def log_parser_end(self): + """ + Logs the parser finished event. + """ self.add_log(_("Load data finished")) def handle_parser_errors(self, errors): + """ + Handles parser errors by logging them and moving the task status to ERROR. + """ for error in errors: self.add_log(f"{str(error)}", save=False) self.status = TagImportTaskState.ERROR.value self.save() def log_start_planning(self): + """ + Starts task planning with a log message, and moves the task status to PLANNING. + """ self.add_log(_("Starting plan actions"), save=False) self.status = TagImportTaskState.PLANNING.value self.save() def log_plan(self, plan): + """ + Logs the task plan. + """ self.add_log(_("Plan finished")) plan_str = plan.plan() self.log += f"\n{plan_str}\n" self.save() def handle_plan_errors(self): + """ + Handles plan errors by moving the task status to ERROR. + """ # Error are logged with plan self.status = TagImportTaskState.ERROR.value self.save() def log_start_execute(self): + """ + Starts task execution with a log message, and moves the task status to EXECUTING. + """ self.add_log(_("Starting execute actions"), save=False) self.status = TagImportTaskState.EXECUTING.value self.save() def end_success(self): + """ + Completes task execution with a log message, and moves the task status to SUCCESS. + """ self.add_log(_("Execution finished"), save=False) self.status = TagImportTaskState.SUCCESS.value self.save() diff --git a/openedx_tagging/core/tagging/rest_api/__init__.py b/openedx_tagging/core/tagging/rest_api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/openedx_tagging/core/tagging/rest_api/paginators.py b/openedx_tagging/core/tagging/rest_api/paginators.py index 6e2fd99f..8848e537 100644 --- a/openedx_tagging/core/tagging/rest_api/paginators.py +++ b/openedx_tagging/core/tagging/rest_api/paginators.py @@ -1,3 +1,7 @@ +""" +Paginators uses by the REST API +""" + from edx_rest_framework_extensions.paginators import DefaultPagination # type: ignore[import] # From this point, the tags begin to be paginated diff --git a/openedx_tagging/core/tagging/rest_api/v1/permissions.py b/openedx_tagging/core/tagging/rest_api/v1/permissions.py index 2e7f921c..ed184549 100644 --- a/openedx_tagging/core/tagging/rest_api/v1/permissions.py +++ b/openedx_tagging/core/tagging/rest_api/v1/permissions.py @@ -6,6 +6,9 @@ class TaxonomyObjectPermissions(DjangoObjectPermissions): + """ + Maps each REST API methods to its corresponding Taxonomy permission. + """ perms_map = { "GET": ["%(app_label)s.view_%(model_name)s"], "OPTIONS": [], @@ -18,6 +21,9 @@ class TaxonomyObjectPermissions(DjangoObjectPermissions): class ObjectTagObjectPermissions(DjangoObjectPermissions): + """ + Maps each REST API methods to its corresponding ObjectTag permission. + """ perms_map = { "GET": ["%(app_label)s.view_%(model_name)s"], "OPTIONS": [], @@ -30,7 +36,13 @@ class ObjectTagObjectPermissions(DjangoObjectPermissions): class TagListPermissions(DjangoObjectPermissions): + """ + Permissions for Tag object views. + """ def has_permission(self, request, view): + """ + Returns True if the user on the given request is allowed the given view. + """ if not request.user or ( not request.user.is_authenticated and self.authenticated_users_only ): @@ -38,4 +50,7 @@ def has_permission(self, request, view): return True def has_object_permission(self, request, view, obj): + """ + Returns True if the user on the given request is allowed the given view for the given object. + """ return rules.has_perm("oel_tagging.list_tag", request.user, obj) diff --git a/openedx_tagging/core/tagging/rest_api/v1/serializers.py b/openedx_tagging/core/tagging/rest_api/v1/serializers.py index cf7d6304..c5472afb 100644 --- a/openedx_tagging/core/tagging/rest_api/v1/serializers.py +++ b/openedx_tagging/core/tagging/rest_api/v1/serializers.py @@ -8,7 +8,7 @@ from openedx_tagging.core.tagging.models import ObjectTag, Tag, Taxonomy -class TaxonomyListQueryParamsSerializer(serializers.Serializer): +class TaxonomyListQueryParamsSerializer(serializers.Serializer): # pylint: disable=abstract-method """ Serializer for the query params for the GET view """ @@ -31,7 +31,7 @@ class Meta: ] -class ObjectTagListQueryParamsSerializer(serializers.Serializer): +class ObjectTagListQueryParamsSerializer(serializers.Serializer): # pylint: disable=abstract-method """ Serializer for the query params for the ObjectTag GET view """ @@ -57,7 +57,7 @@ class Meta: ] -class ObjectTagUpdateBodySerializer(serializers.Serializer): +class ObjectTagUpdateBodySerializer(serializers.Serializer): # pylint: disable=abstract-method """ Serializer of the body for the ObjectTag UPDATE view """ @@ -65,7 +65,7 @@ class ObjectTagUpdateBodySerializer(serializers.Serializer): tags = serializers.ListField(child=serializers.CharField(), required=True) -class ObjectTagUpdateQueryParamsSerializer(serializers.Serializer): +class ObjectTagUpdateQueryParamsSerializer(serializers.Serializer): # pylint: disable=abstract-method """ Serializer of the query params for the ObjectTag UPDATE view """ @@ -97,6 +97,9 @@ class Meta: ) def get_sub_tags_link(self, obj): + """ + Returns URL for the list of child tags of the current tag. + """ if obj.children.count(): query_params = f"?parent_tag_id={obj.id}" url = ( @@ -105,8 +108,12 @@ def get_sub_tags_link(self, obj): ) request = self.context.get("request") return request.build_absolute_uri(url) + return None def get_children_count(self, obj): + """ + Returns the number of child tags of the given tag. + """ return obj.children.count() @@ -131,6 +138,9 @@ class Meta: ) def get_sub_tags(self, obj): + """ + Returns a serialized list of child tags for the given tag. + """ serializer = TagsWithSubTagsSerializer( obj.children.all().order_by("value", "id"), many=True, @@ -139,6 +149,9 @@ def get_sub_tags(self, obj): return serializer.data def get_children_count(self, obj): + """ + Returns the number of child tags of the given tag. + """ return obj.children.count() @@ -150,8 +163,14 @@ class TagsForSearchSerializer(TagsWithSubTagsSerializer): """ def get_sub_tags(self, obj): + """ + Returns a serialized list of child tags for the given tag. + """ serializer = TagsWithSubTagsSerializer(obj.sub_tags, many=True, read_only=True) return serializer.data def get_children_count(self, obj): + """ + Returns the number of child tags of the given tag. + """ return len(obj.sub_tags) diff --git a/openedx_tagging/core/tagging/rest_api/v1/views.py b/openedx_tagging/core/tagging/rest_api/v1/views.py index 26fcad57..f940add1 100644 --- a/openedx_tagging/core/tagging/rest_api/v1/views.py +++ b/openedx_tagging/core/tagging/rest_api/v1/views.py @@ -244,7 +244,7 @@ def get_queryset(self) -> models.QuerySet: taxonomy_id = query_params.data.get("taxonomy", None) return get_object_tags(object_id, taxonomy_id) - def retrieve(self, request, object_id=None): + def retrieve(self, request, *args, **kwargs): """ Retrieve ObjectTags that belong to a given object_id @@ -259,7 +259,7 @@ def retrieve(self, request, object_id=None): serializer = ObjectTagSerializer(object_tags, many=True) return Response(serializer.data) - def update(self, request, object_id, partial=False): + def update(self, request, *args, **kwargs): """ Update ObjectTags that belong to a given object_id @@ -284,6 +284,7 @@ def update(self, request, object_id, partial=False): } """ + partial = kwargs.pop('partial', False) if partial: raise MethodNotAllowed("PATCH", detail="PATCH not allowed") @@ -296,6 +297,7 @@ def update(self, request, object_id, partial=False): perm = f"{taxonomy._meta.app_label}.change_objecttag" + object_id = kwargs.pop('object_id') perm_obj = ChangeObjectTagPermissionItem( taxonomy=taxonomy, object_id=object_id, @@ -313,9 +315,9 @@ def update(self, request, object_id, partial=False): try: tag_object(taxonomy, tags, object_id) except Tag.DoesNotExist as e: - raise ValidationError(e) + raise ValidationError from e except ValueError as e: - raise ValidationError(e) + raise ValidationError from e return self.retrieve(request, object_id) diff --git a/tests/openedx_tagging/core/tagging/test_api.py b/tests/openedx_tagging/core/tagging/test_api.py index 6ed0140a..f82a2201 100644 --- a/tests/openedx_tagging/core/tagging/test_api.py +++ b/tests/openedx_tagging/core/tagging/test_api.py @@ -10,7 +10,7 @@ from django.test import TestCase, override_settings import openedx_tagging.core.tagging.api as tagging_api -from openedx_tagging.core.tagging.models import ObjectTag, Tag, Taxonomy +from openedx_tagging.core.tagging.models import ObjectTag, Taxonomy from .test_models import TestTagTaxonomyMixin, get_tag @@ -186,23 +186,6 @@ def test_get_children_tags(self): self.english_tag, ) - def check_object_tag( - self, - object_tag: ObjectTag, - taxonomy: Taxonomy | None, - tag: Tag | None, - name: str, - value: str, - ) -> None: - """ - Verifies that the properties of the given object_tag (once refreshed from the database) match those given. - """ - object_tag.refresh_from_db() - assert object_tag.taxonomy == taxonomy - assert object_tag.tag == tag - assert object_tag.name == name - assert object_tag.value == value - def test_resync_object_tags(self) -> None: self.taxonomy.allow_multiple = True self.taxonomy.save() @@ -487,8 +470,8 @@ def test_tag_object_limit(self) -> None: ["Eubacteria"], "object_1", ) - assert exc.exception - assert "Cannot add more than 100 tags to" in str(exc.exception) + assert exc.exception + assert "Cannot add more than 100 tags to" in str(exc.exception) # Updating existing tags should work for taxonomy in self.dummy_taxonomies: @@ -506,8 +489,8 @@ def test_tag_object_limit(self) -> None: ["New Dummy Tag 1", "New Dummy Tag 2"], "object_1", ) - assert exc.exception - assert "Cannot add more than 100 tags to" in str(exc.exception) + assert exc.exception + assert "Cannot add more than 100 tags to" in str(exc.exception) def test_get_object_tags(self) -> None: # Alpha tag has no taxonomy diff --git a/tests/openedx_tagging/core/tagging/test_models.py b/tests/openedx_tagging/core/tagging/test_models.py index ccc9e6c6..2a7131f4 100644 --- a/tests/openedx_tagging/core/tagging/test_models.py +++ b/tests/openedx_tagging/core/tagging/test_models.py @@ -144,7 +144,7 @@ def setup_tag_depths(self): tag.depth = 2 -class TestTaxonomySubclassA(Taxonomy): +class TaxonomyTestSubclassA(Taxonomy): """ Model A for testing the taxonomy subclass casting. """ @@ -155,7 +155,7 @@ class Meta: app_label = "oel_tagging" -class TestTaxonomySubclassB(TestTaxonomySubclassA): +class TaxonomyTestSubclassB(TaxonomyTestSubclassA): """ Model B for testing the taxonomy subclass casting. """ @@ -166,7 +166,7 @@ class Meta: app_label = "oel_tagging" -class TestObjectTagSubclass(ObjectTag): +class ObjectTagTestSubclass(ObjectTag): """ Model for testing the ObjectTag copy. """ @@ -200,9 +200,9 @@ def test_representations(self): def test_taxonomy_cast(self): for subclass in ( - TestTaxonomySubclassA, + TaxonomyTestSubclassA, # Ensure that casting to a sub-subclass works as expected - TestTaxonomySubclassB, + TaxonomyTestSubclassB, # and that we can un-set the subclass None, ): @@ -349,11 +349,11 @@ def test_representations(self): ) def test_cast(self): - copy_tag = TestObjectTagSubclass.cast(self.object_tag) + copy_tag = ObjectTagTestSubclass.cast(self.object_tag) assert ( str(copy_tag) == repr(copy_tag) - == " object:id:1: Life on Earth=Bacteria" + == " object:id:1: Life on Earth=Bacteria" ) def test_object_tag_name(self): diff --git a/tests/openedx_tagging/core/tagging/test_system_defined_models.py b/tests/openedx_tagging/core/tagging/test_system_defined_models.py index 09f7b2bc..3c0cb676 100644 --- a/tests/openedx_tagging/core/tagging/test_system_defined_models.py +++ b/tests/openedx_tagging/core/tagging/test_system_defined_models.py @@ -32,7 +32,7 @@ class EmptyTestClass: """ -class TestLPTaxonomy(ModelSystemDefinedTaxonomy): +class LPTaxonomyTest(ModelSystemDefinedTaxonomy): """ Model used for testing - points to LearningPackage instances """ @@ -54,7 +54,7 @@ class Meta: app_label = "oel_tagging" -class CaseInsensitiveTitleLPTaxonomy(TestLPTaxonomy): +class CaseInsensitiveTitleLPTaxonomy(LPTaxonomyTest): """ Model that points to LearningPackage instances but uses 'title' as values """ @@ -89,8 +89,8 @@ def setUpClass(cls): # Create two learning packages and a taxonomy that can tag any object using learning packages as tags: cls.learning_pkg_1 = cls._create_learning_pkg(key="p1", title="Learning Package 1") cls.learning_pkg_2 = cls._create_learning_pkg(key="p2", title="Learning Package 2") - cls.lp_taxonomy = TestLPTaxonomy.objects.create( - taxonomy_class=TestLPTaxonomy, + cls.lp_taxonomy = LPTaxonomyTest.objects.create( + taxonomy_class=LPTaxonomyTest, name="LearningPackage Taxonomy", allow_multiple=True, ) diff --git a/tests/openedx_tagging/core/tagging/test_views.py b/tests/openedx_tagging/core/tagging/test_views.py index b843d204..9183ee5f 100644 --- a/tests/openedx_tagging/core/tagging/test_views.py +++ b/tests/openedx_tagging/core/tagging/test_views.py @@ -585,7 +585,8 @@ def test_object_tags_remaining_http_methods( response = self.client.post(url, {"test": "payload"}, format="json") elif http_method == "PATCH": response = self.client.patch(url, {"test": "payload"}, format="json") - elif http_method == "DELETE": + else: + assert http_method == "DELETE" response = self.client.delete(url) assert response.status_code == expected_status