diff --git a/coldfront/core/allocation/admin.py b/coldfront/core/allocation/admin.py index 972396858b..f48c8de302 100644 --- a/coldfront/core/allocation/admin.py +++ b/coldfront/core/allocation/admin.py @@ -246,11 +246,7 @@ def allocation_status(self, obj): return obj.allocation.status def pi(self, obj): - return "{} {} ({})".format( - obj.allocation.project.pi.first_name, - obj.allocation.project.pi.last_name, - obj.allocation.project.pi.username, - ) + return f"{obj.allocation.project.pi.first_name} {obj.allocation.project.pi.last_name} ({obj.allocation.project.pi.username})" def project(self, obj): return textwrap.shorten(obj.allocation.project.title, width=50) @@ -330,7 +326,7 @@ def allocation_status(self, obj): return obj.allocation.status def user_info(self, obj): - return "{} {} ({})".format(obj.user.first_name, obj.user.last_name, obj.user.username) + return f"{obj.user.first_name} {obj.user.last_name} ({obj.user.username})" def resource(self, obj): return obj.allocation.resources.first() diff --git a/coldfront/core/allocation/forms.py b/coldfront/core/allocation/forms.py index 8068ba43a1..88957aa5fe 100644 --- a/coldfront/core/allocation/forms.py +++ b/coldfront/core/allocation/forms.py @@ -45,7 +45,10 @@ def __init__(self, request_user, project_pk, *args, **kwargs): user_query_set = user_query_set.exclude(user=project_obj.pi) if user_query_set: self.fields["users"].choices = ( - (user.user.username, "%s %s (%s)" % (user.user.first_name, user.user.last_name, user.user.username)) + ( + user.user.username, + f"{user.user.first_name} {user.user.last_name} ({user.user.username})", + ) for user in user_query_set ) self.fields["users"].help_text = "
Select users in your project to add to this allocation." @@ -229,7 +232,7 @@ def clean(self): class AllocationChangeForm(forms.Form): EXTENSION_CHOICES = [(0, "No Extension")] for choice in ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS: - EXTENSION_CHOICES.append((choice, "{} days".format(choice))) + EXTENSION_CHOICES.append((choice, f"{choice} days")) end_date_extension = forms.TypedChoiceField( label="Request End Date Extension", @@ -265,7 +268,7 @@ class Meta: fields = "__all__" def __init__(self, *args, **kwargs): - super(AllocationAttributeCreateForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["allocation_attribute_type"].queryset = self.fields["allocation_attribute_type"].queryset.order_by( Lower("name") ) diff --git a/coldfront/core/allocation/models.py b/coldfront/core/allocation/models.py index 3e6ef9bf9d..20605f5356 100644 --- a/coldfront/core/allocation/models.py +++ b/coldfront/core/allocation/models.py @@ -175,12 +175,7 @@ def get_information(self): "Allocation attribute '%s' == 0 but has a usage", attribute.allocation_attribute_type.name ) - string = "{}: {}/{} ({} %)
".format( - attribute.allocation_attribute_type.name, - attribute.allocationattributeusage.value, - attribute.value, - percent, - ) + string = f"{attribute.allocation_attribute_type.name}: {attribute.allocationattributeusage.value}/{attribute.value} ({percent} %)
" html_string += string return mark_safe(html_string) @@ -340,7 +335,7 @@ def has_perm(self, user, perm): return perm in perms def __str__(self): - return "%s (%s)" % (self.get_parent_resource.name, self.project.pi) + return f"{self.get_parent_resource.name} ({self.project.pi})" def get_eula(self): if self.get_resources_as_list: @@ -428,7 +423,7 @@ class AllocationAttributeType(TimeStampedModel): history = HistoricalRecords() def __str__(self): - return "%s" % (self.name) + return self.name class Meta: ordering = [ @@ -469,40 +464,34 @@ def clean(self): .exclude(id=self.pk) .exists() ): - raise ValidationError( - "'{}' attribute already exists for this allocation.".format(self.allocation_attribute_type) - ) + raise ValidationError(f"'{self.allocation_attribute_type}' attribute already exists for this allocation.") expected_value_type = self.allocation_attribute_type.attribute_type.name.strip() if expected_value_type == "Int" and not isinstance(literal_eval(self.value), int): raise ValidationError( - 'Invalid Value "%s" for "%s". Value must be an integer.' - % (self.value, self.allocation_attribute_type.name) + f'Invalid Value "{self.value}" for "{self.allocation_attribute_type.name}". Value must be an integer.' ) elif expected_value_type == "Float" and not ( isinstance(literal_eval(self.value), float) or isinstance(literal_eval(self.value), int) ): raise ValidationError( - 'Invalid Value "%s" for "%s". Value must be a float.' - % (self.value, self.allocation_attribute_type.name) + f'Invalid Value "{self.value}" for "{self.allocation_attribute_type.name}". Value must be a float.' ) elif expected_value_type == "Yes/No" and self.value not in ["Yes", "No"]: raise ValidationError( - 'Invalid Value "%s" for "%s". Allowed inputs are "Yes" or "No".' - % (self.value, self.allocation_attribute_type.name) + f'Invalid Value "{self.value}" for "{self.allocation_attribute_type.name}". Allowed inputs are "Yes" or "No".' ) elif expected_value_type == "Date": try: datetime.datetime.strptime(self.value.strip(), "%Y-%m-%d") except ValueError: raise ValidationError( - 'Invalid Value "%s" for "%s". Date must be in format YYYY-MM-DD' - % (self.value, self.allocation_attribute_type.name) + f'Invalid Value "{self.value}" for "{self.allocation_attribute_type.name}". Date must be in format YYYY-MM-DD' ) def __str__(self): - return "%s" % (self.allocation_attribute_type.name) + return self.allocation_attribute_type.name def typed_value(self): """ @@ -572,7 +561,7 @@ class AllocationAttributeUsage(TimeStampedModel): history = HistoricalRecords() def __str__(self): - return "{}: {}".format(self.allocation_attribute.allocation_attribute_type.name, self.value) + return f"{self.allocation_attribute.allocation_attribute_type.name}: {self.value}" class AllocationUserStatusChoice(TimeStampedModel): @@ -631,7 +620,7 @@ def is_active(self): return self.status.name == "Active" and self.allocation.status.name in active_allocation_statuses def __str__(self): - return "%s" % (self.user) + return str(self.user) class Meta: verbose_name_plural = "Allocation User Status" @@ -711,7 +700,7 @@ def get_parent_resource(self): return self.allocation.resources.filter(is_allocatable=True).first() def __str__(self): - return "%s (%s)" % (self.get_parent_resource.name, self.allocation.project.pi) + return f"{self.get_parent_resource.name} ({self.allocation.project.pi})" class AllocationAttributeChangeRequest(TimeStampedModel): @@ -729,4 +718,4 @@ class AllocationAttributeChangeRequest(TimeStampedModel): history = HistoricalRecords() def __str__(self): - return "%s" % (self.allocation_attribute.allocation_attribute_type.name) + return str(self.allocation_attribute.allocation_attribute_type.name) diff --git a/coldfront/core/allocation/tasks.py b/coldfront/core/allocation/tasks.py index 883420aee0..e34531587c 100644 --- a/coldfront/core/allocation/tasks.py +++ b/coldfront/core/allocation/tasks.py @@ -50,7 +50,7 @@ def update_statuses(): sub_obj.status = expired_status_choice sub_obj.save() - logger.info("Allocations set to expired: {}".format(allocations_to_expire.count())) + logger.info(f"Allocations set to expired: {allocations_to_expire.count()}") def send_eula_reminders(): diff --git a/coldfront/core/allocation/tests/test_models.py b/coldfront/core/allocation/tests/test_models.py index 0363a74302..0cfb64c09b 100644 --- a/coldfront/core/allocation/tests/test_models.py +++ b/coldfront/core/allocation/tests/test_models.py @@ -37,7 +37,7 @@ def setUpTestData(cls): def test_allocation_str(self): """test that allocation str method returns correct string""" - allocation_str = "%s (%s)" % (self.allocation.get_parent_resource.name, self.allocation.project.pi) + allocation_str = f"{self.allocation.get_parent_resource.name} ({self.allocation.project.pi})" self.assertEqual(str(self.allocation), allocation_str) diff --git a/coldfront/core/allocation/tests/test_views.py b/coldfront/core/allocation/tests/test_views.py index e01b870c79..62de1e0768 100644 --- a/coldfront/core/allocation/tests/test_views.py +++ b/coldfront/core/allocation/tests/test_views.py @@ -75,7 +75,7 @@ class AllocationListViewTest(AllocationViewBaseTest): @classmethod def setUpTestData(cls): """Set up users and project for testing""" - super(AllocationListViewTest, cls).setUpTestData() + super().setUpTestData() cls.additional_allocations = [AllocationFactory() for i in list(range(100))] for allocation in cls.additional_allocations: allocation.resources.add(ResourceFactory(name="holylfs09/tier1")) diff --git a/coldfront/core/allocation/utils.py b/coldfront/core/allocation/utils.py index d091d0aad4..7aec3979d0 100644 --- a/coldfront/core/allocation/utils.py +++ b/coldfront/core/allocation/utils.py @@ -16,7 +16,7 @@ def set_allocation_user_status_to_error(allocation_user_pk): def generate_guauge_data_from_usage(name, value, usage): - label = "%s: %.2f of %.2f" % (name, usage, value) + label = f"{name}: {usage:.2f} of {value:.2f}" try: percent = (usage / value) * 100 diff --git a/coldfront/core/allocation/views.py b/coldfront/core/allocation/views.py index 02c129d267..4c60d22ec7 100644 --- a/coldfront/core/allocation/views.py +++ b/coldfront/core/allocation/views.py @@ -317,12 +317,7 @@ def post(self, request, *args, **kwargs): if action == "auto-approve": messages.success( request, - "Allocation to {} has been ACTIVATED for {} {} ({})".format( - allocation_obj.get_parent_resource, - allocation_obj.project.pi.first_name, - allocation_obj.project.pi.last_name, - allocation_obj.project.pi.username, - ), + f"Allocation to {allocation_obj.get_parent_resource} has been ACTIVATED for {allocation_obj.project.pi.first_name} {allocation_obj.project.pi.last_name} ({allocation_obj.project.pi.username})", ) return HttpResponseRedirect(reverse("allocation-request-list")) @@ -567,7 +562,8 @@ def get_context_data(self, **kwargs): order_by = self.request.GET.get("order_by") if order_by: direction = self.request.GET.get("direction") - filter_parameters_with_order_by = filter_parameters + "order_by=%s&direction=%s&" % (order_by, direction) + filter_parameters_string = "" if not filter_parameters else filter_parameters + filter_parameters_with_order_by = filter_parameters_string + f"order_by={order_by}&direction={direction}&" else: filter_parameters_with_order_by = filter_parameters @@ -1814,12 +1810,7 @@ def post(self, request, *args, **kwargs): messages.success( request, - "Allocation change request to {} has been DENIED for {} {} ({})".format( - allocation_change_obj.allocation.resources.first(), - allocation_change_obj.allocation.project.pi.first_name, - allocation_change_obj.allocation.project.pi.last_name, - allocation_change_obj.allocation.project.pi.username, - ), + f"Allocation change request to {allocation_change_obj.allocation.resources.first()} has been DENIED for {allocation_change_obj.allocation.project.pi.first_name} {allocation_change_obj.allocation.project.pi.last_name} ({allocation_change_obj.allocation.project.pi.username})", ) send_allocation_customer_email( @@ -1894,12 +1885,7 @@ def post(self, request, *args, **kwargs): messages.success( request, - "Allocation change request to {} has been APPROVED for {} {} ({})".format( - allocation_change_obj.allocation.get_parent_resource, - allocation_change_obj.allocation.project.pi.first_name, - allocation_change_obj.allocation.project.pi.last_name, - allocation_change_obj.allocation.project.pi.username, - ), + f"Allocation change request to {allocation_change_obj.allocation.get_parent_resource} has been APPROVED for {allocation_change_obj.allocation.project.pi.first_name} {allocation_change_obj.allocation.project.pi.last_name} ({allocation_change_obj.allocation.project.pi.username})", ) allocation_change_approved.send( diff --git a/coldfront/core/attribute_expansion.py b/coldfront/core/attribute_expansion.py index 68260536f2..7a35e32f79 100644 --- a/coldfront/core/attribute_expansion.py +++ b/coldfront/core/attribute_expansion.py @@ -44,7 +44,7 @@ def get_attriblist_str(attribute_name, resources=[], allocations=[]): attriblist attributes are found, we return None. """ - attriblist_name = "{aname}{suffix}".format(aname=attribute_name, suffix=ATTRIBUTE_EXPANSION_ATTRIBLIST_SUFFIX) + attriblist_name = f"{attribute_name}{ATTRIBUTE_EXPANSION_ATTRIBLIST_SUFFIX}" attriblist = None # Check resources first @@ -115,9 +115,7 @@ def get_attribute_parameter_value(argument, attribute_parameter_dict, error_text else: # Bad string literal logger.warning( - "Bad string literal '{}' found while processing {}; missing final single quote".format( - argument, error_text - ) + f"Bad string literal '{argument}' found while processing {error_text}; missing final single quote" ) return None @@ -167,11 +165,7 @@ def get_attribute_parameter_value(argument, attribute_parameter_dict, error_text value = float(argument) return value except ValueError: - logger.warning( - "Unable to evaluate argument '{arg}' while processing {etxt}, returning None".format( - arg=argument, etxt=error_text - ) - ) + logger.warning(f"Unable to evaluate argument '{argument}' while processing {error_text}, returning None") return None # Should not reach here @@ -214,12 +208,12 @@ def process_attribute_parameter_operation(opcode, oldvalue, argument, error_text """ # Argument should never be None if argument is None: - logger.warning("Operator {}= acting on None argument in {}, returning None".format(opcode, error_text)) + logger.warning(f"Operator {opcode}= acting on None argument in {error_text}, returning None") return None # Assignment and default operations allow oldvalue to be None if oldvalue is None: if opcode != ":" and opcode != "|": - logger.warning("Operator {}= acting on oldvalue=None in {}, returning None".format(opcode, error_text)) + logger.warning(f"Operator {opcode}= acting on oldvalue=None in {error_text}, returning None") return None try: @@ -242,9 +236,7 @@ def process_attribute_parameter_operation(opcode, oldvalue, argument, error_text return newval else: logger.warning( - "Operator {}= acting on parameter of type {} in {}, returning None".format( - opcode, type(oldvalue), error_text - ) + f"Operator {opcode}= acting on parameter of type {type(oldvalue)} in {error_text}, returning None" ) return None if opcode == "-": @@ -260,17 +252,13 @@ def process_attribute_parameter_operation(opcode, oldvalue, argument, error_text if argument == "floor": newval = math.floor(oldvalue) else: - logger.error( - "Unrecognized function named {} in {}= for {}, returning None".format(argument, opcode, error_text) - ) + logger.error(f"Unrecognized function named {argument} in {opcode}= for {error_text}, returning None") return None # If reached here, we do not recognize opcode - logger.error("Unrecognized operation {}= in {}, returning None".format(opcode, error_text)) + logger.error(f"Unrecognized operation {opcode}= in {error_text}, returning None") except Exception: logger.warning( - "Error performing operator {op}= on oldvalue='{old}' and argument={arg} in {errtext}".format( - op=opcode, old=oldvalue, arg=argument, errtext=error_text - ) + f"Error performing operator {opcode}= on oldvalue='{oldvalue}' and argument={argument} in {error_text}" ) return None @@ -320,9 +308,9 @@ def process_attribute_parameter_string( # No '=' found, so invalid format of parmstr # Log error and return unmodified attribute_parameter_dict logger.error( - "Invalid parameter string '{pstr}', no '=', while " + f"Invalid parameter string '{parameter_string}', no '=', while " "creating attribute parameter dictionary for expanding " - "attribute {aname}".format(aname=attribute_name, pstr=parameter_string) + f"attribute {attribute_name}" ) return attribute_parameter_dict pname = tmp[0] @@ -338,8 +326,8 @@ def process_attribute_parameter_string( value = argument else: # Extra text to display in diagnostics if error occurs - error_text = "processing attribute_parameter_string={pstr} for expansion of attribute {aname}".format( - pstr=parameter_string, aname=attribute_name + error_text = ( + f"processing attribute_parameter_string={parameter_string} for expansion of attribute {attribute_name}" ) value = get_attribute_parameter_value( argument=argument, @@ -463,7 +451,7 @@ def expand_attribute(raw_value, attribute_name, attriblist_string, resources=[], # referencing a parameter not defined in apdict to divide by # zero errors in processing apdict. We just log it and then # return raw_value - logger.error("Error expanding {aname}: {error}".format(aname=attribute_name, error=xcept)) + logger.error(f"Error expanding {attribute_name}: {xcept}") return raw_value @@ -485,7 +473,7 @@ def convert_type(value, type_name, error_text="unknown"): future "Attribute Expanded ..." types. """ if type_name is None: - logger.error("No AttributeType found for {}".format(error_text)) + logger.error(f"No AttributeType found for {error_text}") return value if type_name.endswith("Text"): diff --git a/coldfront/core/field_of_science/management/commands/import_field_of_science_data.py b/coldfront/core/field_of_science/management/commands/import_field_of_science_data.py index f71e1f0038..0d5625b86c 100644 --- a/coldfront/core/field_of_science/management/commands/import_field_of_science_data.py +++ b/coldfront/core/field_of_science/management/commands/import_field_of_science_data.py @@ -18,7 +18,7 @@ def handle(self, *args, **options): self.stdout.write("Adding field of science ...") file_path = os.path.join(app_commands_dir, "data", "field_of_science_data.csv") FieldOfScience.objects.all().delete() - with open(file_path, "r") as fp: + with open(file_path) as fp: for line in fp: pk, parent_id, is_selectable, description, fos_nsf_id, fos_nsf_abbrev, directorate_fos_id = ( line.strip().split("\t") diff --git a/coldfront/core/grant/admin.py b/coldfront/core/grant/admin.py index b77b71f36c..8c5bd4561b 100644 --- a/coldfront/core/grant/admin.py +++ b/coldfront/core/grant/admin.py @@ -58,7 +58,7 @@ class GrantAdmin(SimpleHistoryAdmin): ] def Project_PI(self, obj): - return "{} {} ({})".format(obj.project.pi.first_name, obj.project.pi.last_name, obj.project.pi.username) + return f"{obj.project.pi.first_name} {obj.project.pi.last_name} ({obj.project.pi.username})" def Funding_Agency(self, obj): if obj.funding_agency.name == "Other": diff --git a/coldfront/core/grant/forms.py b/coldfront/core/grant/forms.py index f40024b357..a78ab7c03b 100644 --- a/coldfront/core/grant/forms.py +++ b/coldfront/core/grant/forms.py @@ -18,19 +18,17 @@ class Meta: "project", ] labels = { - "percent_credit": "Percent credit to {}".format(CENTER_NAME), - "direct_funding": "Direct funding to {}".format(CENTER_NAME), + "percent_credit": f"Percent credit to {CENTER_NAME}", + "direct_funding": f"Direct funding to {CENTER_NAME}", } help_texts = { "percent_credit": "Percent credit as entered in the sponsored projects form for grant submission as financial credit to the department/unit in the credit distribution section. Enter only digits, decimals, percent symbols, or spaces.", - "direct_funding": "Funds budgeted specifically for {} services, hardware, software, and/or personnel. Enter only digits, decimals, commas, dollar signs, or spaces.".format( - CENTER_NAME - ), + "direct_funding": f"Funds budgeted specifically for {CENTER_NAME} services, hardware, software, and/or personnel. Enter only digits, decimals, commas, dollar signs, or spaces.", "total_amount_awarded": "Enter only digits, decimals, commas, dollar signs, or spaces.", } def __init__(self, *args, **kwargs): - super(GrantForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["funding_agency"].queryset = self.fields["funding_agency"].queryset.order_by("name") diff --git a/coldfront/core/grant/models.py b/coldfront/core/grant/models.py index d1fa1b28f4..9c7c4e5a04 100644 --- a/coldfront/core/grant/models.py +++ b/coldfront/core/grant/models.py @@ -152,7 +152,7 @@ def grant_pi(self): """ if self.role == "PI": - return "{} {}".format(self.project.pi.first_name, self.project.pi.last_name) + return f"{self.project.pi.first_name} {self.project.pi.last_name}" else: return self.grant_pi_full_name diff --git a/coldfront/core/grant/views.py b/coldfront/core/grant/views.py index ed6f075d53..4e385529d1 100644 --- a/coldfront/core/grant/views.py +++ b/coldfront/core/grant/views.py @@ -188,7 +188,7 @@ def post(self, request, *args, **kwargs): grant_obj.delete() grants_deleted_count += 1 - messages.success(request, "Deleted {} grants from project.".format(grants_deleted_count)) + messages.success(request, f"Deleted {grants_deleted_count} grants from project.") else: for error in formset.errors: messages.error(request, error) diff --git a/coldfront/core/portal/utils.py b/coldfront/core/portal/utils.py index 5ddacaff98..8a63369efe 100644 --- a/coldfront/core/portal/utils.py +++ b/coldfront/core/portal/utils.py @@ -30,10 +30,10 @@ def generate_total_grants_by_agency_chart_data(total_grants_by_agency): def generate_resources_chart_data(allocations_count_by_resource_type): if allocations_count_by_resource_type: - cluster_label = "Cluster: %d" % (allocations_count_by_resource_type.get("Cluster", 0)) - cloud_label = "Cloud: %d" % (allocations_count_by_resource_type.get("Cloud", 0)) - server_label = "Server: %d" % (allocations_count_by_resource_type.get("Server", 0)) - storage_label = "Storage: %d" % (allocations_count_by_resource_type.get("Storage", 0)) + cluster_label = f"Cluster: {allocations_count_by_resource_type.get('Cluster', 0)}" + cloud_label = f"Cloud: {allocations_count_by_resource_type.get('Cloud', 0)}" + server_label = f"Server: {allocations_count_by_resource_type.get('Server', 0)}" + storage_label = f"Storage: {allocations_count_by_resource_type.get('Storage', 0)}" resource_plot_data = { "columns": [ @@ -65,10 +65,10 @@ def generate_allocations_chart_data(): start_time = datetime.date(now.year - 1, 1, 1) expired_count = Allocation.objects.filter(status__name="Expired", end_date__gte=start_time).count() - active_label = "Active: %d" % (active_count) - new_label = "New: %d" % (new_count) - renewal_requested_label = "Renewal Requested: %d" % (renewal_requested_count) - expired_label = "Expired: %d" % (expired_count) + active_label = f"Active: {active_count}" + new_label = f"New: {new_count}" + renewal_requested_label = f"Renewal Requested: {renewal_requested_count}" + expired_label = f"Expired: {expired_count}" allocation_chart_data = { "columns": [ diff --git a/coldfront/core/project/admin.py b/coldfront/core/project/admin.py index 400df4824c..00ba5b8e3f 100644 --- a/coldfront/core/project/admin.py +++ b/coldfront/core/project/admin.py @@ -77,10 +77,10 @@ def project_title(self, obj): return textwrap.shorten(obj.project.title, width=50) def PI(self, obj): - return "{} {} ({})".format(obj.project.pi.first_name, obj.project.pi.last_name, obj.project.pi.username) + return f"{obj.project.pi.first_name} {obj.project.pi.last_name} ({obj.project.pi.username})" def User(self, obj): - return "{} {} ({})".format(obj.user.first_name, obj.user.last_name, obj.user.username) + return f"{obj.user.first_name} {obj.user.last_name} ({obj.user.username})" def get_fields(self, request, obj): if obj is None: @@ -229,7 +229,7 @@ def project_status(self, obj): return obj.project.status def pi(self, obj): - return "{} {} ({})".format(obj.project.pi.first_name, obj.project.pi.last_name, obj.project.pi.username) + return f"{obj.project.pi.first_name} {obj.project.pi.last_name} ({obj.project.pi.username})" def project(self, obj): return textwrap.shorten(obj.project.title, width=50) @@ -341,7 +341,7 @@ class ProjectAdmin(SimpleHistoryAdmin): ] def PI(self, obj): - return "{} {} ({})".format(obj.pi.first_name, obj.pi.last_name, obj.pi.username) + return f"{obj.pi.first_name} {obj.pi.last_name} ({obj.pi.username})" def get_fields(self, request, obj): if obj is None: @@ -398,4 +398,4 @@ class ProjectReviewAdmin(SimpleHistoryAdmin): list_filter = ("status",) def PI(self, obj): - return "{} {} ({})".format(obj.project.pi.first_name, obj.project.pi.last_name, obj.project.pi.username) + return f"{obj.project.pi.first_name} {obj.project.pi.last_name} ({obj.project.pi.username})" diff --git a/coldfront/core/project/forms.py b/coldfront/core/project/forms.py index a861b6918d..5ae473670d 100644 --- a/coldfront/core/project/forms.py +++ b/coldfront/core/project/forms.py @@ -56,8 +56,7 @@ def __init__(self, request_user, project_pk, *args, **kwargs): allocation_choices = [ ( allocation.id, - "%s (%s) %s" - % ( + "{} ({}) {}".format( allocation.get_parent_resource.name, allocation.get_parent_resource.resource_type.name, allocation.description if allocation.description else "", @@ -108,7 +107,7 @@ class ProjectReviewForm(forms.Form): def __init__(self, project_pk, *args, **kwargs): super().__init__(*args, **kwargs) project_obj = get_object_or_404(Project, pk=project_pk) - now = datetime.datetime.now(datetime.timezone.utc) + now = datetime.datetime.now(datetime.UTC) if project_obj.grant_set.exists(): latest_grant = project_obj.grant_set.order_by("-modified")[0] @@ -135,11 +134,9 @@ class ProjectReviewEmailForm(forms.Form): def __init__(self, pk, *args, **kwargs): super().__init__(*args, **kwargs) project_review_obj = get_object_or_404(ProjectReview, pk=int(pk)) - self.fields["email_body"].initial = "Dear {} {} \n{}".format( - project_review_obj.project.pi.first_name, - project_review_obj.project.pi.last_name, - EMAIL_DIRECTOR_PENDING_PROJECT_REVIEW_EMAIL, - ) + self.fields[ + "email_body" + ].initial = f"Dear {project_review_obj.project.pi.first_name} {project_review_obj.project.pi.last_name} \n{EMAIL_DIRECTOR_PENDING_PROJECT_REVIEW_EMAIL}" self.fields["cc"].initial = ", ".join([EMAIL_DIRECTOR_EMAIL_ADDRESS] + EMAIL_ADMIN_LIST) @@ -152,7 +149,7 @@ class Meta: } def __init__(self, *args, **kwargs): - super(ProjectAttributeAddForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) user = (kwargs.get("initial")).get("user") self.fields["proj_attr_type"].queryset = self.fields["proj_attr_type"].queryset.order_by(Lower("name")) if not user.is_superuser: diff --git a/coldfront/core/project/models.py b/coldfront/core/project/models.py index db2341a531..0b0cd9634d 100644 --- a/coldfront/core/project/models.py +++ b/coldfront/core/project/models.py @@ -168,7 +168,7 @@ def needs_review(self): if self.status.name == "Archived": return False - now = datetime.datetime.now(datetime.timezone.utc) + now = datetime.datetime.now(datetime.UTC) if self.force_review is True: return True @@ -384,7 +384,7 @@ class ProjectUser(TimeStampedModel): history = HistoricalRecords() def __str__(self): - return "%s %s (%s)" % (self.user.first_name, self.user.last_name, self.user.username) + return f"{self.user.first_name} {self.user.last_name} ({self.user.username})" class Meta: unique_together = ("user", "project") @@ -432,7 +432,7 @@ class ProjectAttributeType(TimeStampedModel): history = HistoricalRecords() def __str__(self): - return "%s (%s)" % (self.name, self.attribute_type.name) + return f"{self.name} ({self.attribute_type.name})" def __repr__(self) -> str: return str(self) @@ -470,7 +470,7 @@ def clean(self): self.proj_attr_type.is_unique and self.project.projectattribute_set.filter(proj_attr_type=self.proj_attr_type).exists() ): - raise ValidationError("'{}' attribute already exists for this project.".format(self.proj_attr_type)) + raise ValidationError(f"'{self.proj_attr_type}' attribute already exists for this project.") expected_value_type = self.proj_attr_type.attribute_type.name.strip() @@ -486,7 +486,7 @@ def clean(self): validator.validate_date() def __str__(self): - return "%s" % (self.proj_attr_type.name) + return str(self.proj_attr_type.name) class ProjectAttributeUsage(TimeStampedModel): @@ -502,4 +502,4 @@ class ProjectAttributeUsage(TimeStampedModel): history = HistoricalRecords() def __str__(self): - return "{}: {}".format(self.project_attribute.proj_attr_type.name, self.value) + return f"{self.project_attribute.proj_attr_type.name}: {self.value}" diff --git a/coldfront/core/project/tests/test_views.py b/coldfront/core/project/tests/test_views.py index 116fdd2619..b3a8268760 100644 --- a/coldfront/core/project/tests/test_views.py +++ b/coldfront/core/project/tests/test_views.py @@ -61,7 +61,7 @@ class ProjectDetailViewTest(ProjectViewTestBase): @classmethod def setUpTestData(cls): """Set up users and project for testing""" - super(ProjectDetailViewTest, cls).setUpTestData() + super().setUpTestData() cls.url = f"/project/{cls.project.pk}/" def test_projectdetail_access(self): @@ -121,7 +121,7 @@ class ProjectCreateTest(ProjectViewTestBase): @classmethod def setUpTestData(cls): """Set up users and project for testing""" - super(ProjectCreateTest, cls).setUpTestData() + super().setUpTestData() cls.url = "/project/create/" def test_project_access(self): @@ -140,7 +140,7 @@ class ProjectAttributeCreateTest(ProjectViewTestBase): @classmethod def setUpTestData(cls): """Set up users and project for testing""" - super(ProjectAttributeCreateTest, cls).setUpTestData() + super().setUpTestData() int_attributetype = PAttributeTypeFactory(name="Int") cls.int_projectattributetype = ProjectAttributeTypeFactory(attribute_type=int_attributetype) cls.url = f"/project/{cls.project.pk}/project-attribute-create/" @@ -198,7 +198,7 @@ class ProjectAttributeUpdateTest(ProjectViewTestBase): @classmethod def setUpTestData(cls): """Set up users and project for testing""" - super(ProjectAttributeUpdateTest, cls).setUpTestData() + super().setUpTestData() cls.projectattribute = ProjectAttributeFactory( value=36238, proj_attr_type=cls.projectattributetype, project=cls.project ) @@ -219,7 +219,7 @@ class ProjectAttributeDeleteTest(ProjectViewTestBase): @classmethod def setUpTestData(cls): """set up users and project for testing""" - super(ProjectAttributeDeleteTest, cls).setUpTestData() + super().setUpTestData() cls.projectattribute = ProjectAttributeFactory( value=36238, proj_attr_type=cls.projectattributetype, project=cls.project ) @@ -242,7 +242,7 @@ class ProjectListViewTest(ProjectViewTestBase): @classmethod def setUpTestData(cls): """Set up users and project for testing""" - super(ProjectListViewTest, cls).setUpTestData() + super().setUpTestData() # add 100 projects to test pagination, permissions, search functionality additional_projects = [ProjectFactory() for i in list(range(100))] cls.additional_projects = [p for p in additional_projects if p.pi.last_name != cls.project.pi.last_name] diff --git a/coldfront/core/project/views.py b/coldfront/core/project/views.py index df2adc82f3..9728a6f9b9 100644 --- a/coldfront/core/project/views.py +++ b/coldfront/core/project/views.py @@ -340,9 +340,9 @@ def get_context_data(self, **kwargs): if value: if isinstance(value, list): for ele in value: - filter_parameters += "{}={}&".format(key, ele) + filter_parameters += f"{key}={ele}&" else: - filter_parameters += "{}={}&".format(key, value) + filter_parameters += f"{key}={value}&" context["project_search_form"] = project_search_form else: filter_parameters = None @@ -351,7 +351,8 @@ def get_context_data(self, **kwargs): order_by = self.request.GET.get("order_by") if order_by: direction = self.request.GET.get("direction") - filter_parameters_with_order_by = filter_parameters + "order_by=%s&direction=%s&" % (order_by, direction) + filter_parameters_string = "" if not filter_parameters else filter_parameters + filter_parameters_with_order_by = filter_parameters_string + f"order_by={order_by}&direction={direction}&" else: filter_parameters_with_order_by = filter_parameters @@ -483,9 +484,9 @@ def get_context_data(self, **kwargs): if value: if isinstance(value, list): for ele in value: - filter_parameters += "{}={}&".format(key, ele) + filter_parameters += f"{key}={ele}&" else: - filter_parameters += "{}={}&".format(key, value) + filter_parameters += f"{key}={value}&" context["project_search_form"] = project_search_form else: filter_parameters = None @@ -494,7 +495,8 @@ def get_context_data(self, **kwargs): order_by = self.request.GET.get("order_by") if order_by: direction = self.request.GET.get("direction") - filter_parameters_with_order_by = filter_parameters + "order_by=%s&direction=%s&" % (order_by, direction) + filter_parameters_string = "" if not filter_parameters else filter_parameters + filter_parameters_with_order_by = filter_parameters_string + f"order_by={order_by}&direction={direction}&" else: filter_parameters_with_order_by = filter_parameters @@ -888,7 +890,7 @@ def post(self, request, *args, **kwargs): sender=self.__class__, allocation_user_pk=allocation_user_obj.pk ) - messages.success(request, "Added {} users to project.".format(added_users_count)) + messages.success(request, f"Added {added_users_count} users to project.") else: if not formset.is_valid(): for error in formset.errors: @@ -1010,9 +1012,9 @@ def post(self, request, *args, **kwargs): ) if remove_users_count == 1: - messages.success(request, "Removed {} user from project.".format(remove_users_count)) + messages.success(request, f"Removed {remove_users_count} user from project.") else: - messages.success(request, "Removed {} users from project.".format(remove_users_count)) + messages.success(request, f"Removed {remove_users_count} users from project.") else: for error in formset.errors: messages.error(request, error) @@ -1192,7 +1194,7 @@ def get(self, request, *args, **kwargs): context["project_review_form"] = project_review_form context["project_users"] = ", ".join( [ - "{} {}".format(ele.user.first_name, ele.user.last_name) + f"{ele.user.first_name} {ele.user.last_name}" for ele in project_obj.projectuser_set.filter(status__name="Active").order_by("user__last_name") ] ) @@ -1282,7 +1284,7 @@ def get(self, request, project_review_pk): project_review_obj.project.project_needs_review = False project_review_obj.save() - messages.success(request, "Project review for {} has been completed".format(project_review_obj.project.title)) + messages.success(request, f"Project review for {project_review_obj.project.title} has been completed") return HttpResponseRedirect(reverse("project-review-list")) @@ -1335,11 +1337,7 @@ def form_valid(self, form): messages.success( self.request, - "Email sent to {} {} ({})".format( - project_review_obj.project.pi.first_name, - project_review_obj.project.pi.last_name, - project_review_obj.project.pi.username, - ), + f"Email sent to {project_review_obj.project.pi.first_name} {project_review_obj.project.pi.last_name} ({project_review_obj.project.pi.username})", ) return super().form_valid(form) @@ -1501,7 +1499,7 @@ def post(self, request, *args, **kwargs): proj_attr.delete() - messages.success(request, "Deleted {} attributes from project.".format(attributes_deleted_count)) + messages.success(request, f"Deleted {attributes_deleted_count} attributes from project.") else: for error in formset.errors: messages.error(request, error) diff --git a/coldfront/core/publication/tests/tests.py b/coldfront/core/publication/tests/tests.py index 249840082a..aeb65263ca 100644 --- a/coldfront/core/publication/tests/tests.py +++ b/coldfront/core/publication/tests/tests.py @@ -52,7 +52,7 @@ def __init__(self): def setUp(self): self.data = self.Data() - self.unique_id_generator = ("unique_id_{}".format(id) for id in itertools.count()) + self.unique_id_generator = (f"unique_id_{id}" for id in itertools.count()) def test_fields_generic(self): self.assertEqual(0, len(Publication.objects.all())) @@ -168,7 +168,7 @@ def mock_parse(thing_to_parse): bibtexparser_cls.return_value.parse.side_effect = mock_parse as_text = Mock(spec_set=bibtexparser.bibdatabase.as_text) - as_text.side_effect = lambda bib_entry: "as_text({})".format(bib_entry) + as_text.side_effect = lambda bib_entry: f"as_text({bib_entry})" self.crossref = crossref self.bibtexparser_cls = bibtexparser_cls @@ -178,7 +178,7 @@ def mock_parse(thing_to_parse): def patch(self): def dotpath(qualname): module_under_test = coldfront.core.publication.views - return "{}.{}".format(module_under_test.__name__, qualname) + return f"{module_under_test.__name__}.{qualname}" with contextlib.ExitStack() as stack: patches = [ diff --git a/coldfront/core/publication/views.py b/coldfront/core/publication/views.py index 6cb8f36cfc..711e39f9d1 100644 --- a/coldfront/core/publication/views.py +++ b/coldfront/core/publication/views.py @@ -114,9 +114,7 @@ def _search_id(self, unique_id): elif source.name == "adsabs": try: - url = "http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode={}&data_type=BIBTEX".format( - unique_id - ) + url = f"http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode={unique_id}&data_type=BIBTEX" r = requests.get(url, timeout=5) bp = BibTexParser(interpolate_strings=False) bib_database = bp.parse(r.text) @@ -167,7 +165,7 @@ def _search_id(self, unique_id): else: # fallback: clearly indicate that data was absent source_name = matching_source_obj.name - journal = "[no journal info from {}]".format(source_name.upper()) + journal = f"[no journal info from {source_name.upper()}]" pub_dict = {} pub_dict["author"] = author @@ -408,7 +406,7 @@ def post(self, request, *args, **kwargs): publication_obj.delete() publications_deleted_count += 1 - messages.success(request, "Deleted {} publications from project.".format(publications_deleted_count)) + messages.success(request, f"Deleted {publications_deleted_count} publications from project.") else: for error in formset.errors: messages.error(request, error) diff --git a/coldfront/core/resource/forms.py b/coldfront/core/resource/forms.py index 6a711f35b0..686efebd9b 100644 --- a/coldfront/core/resource/forms.py +++ b/coldfront/core/resource/forms.py @@ -46,7 +46,7 @@ class Meta: fields = "__all__" def __init__(self, *args, **kwargs): - super(ResourceAttributeCreateForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["resource_attribute_type"].queryset = self.fields["resource_attribute_type"].queryset.order_by( Lower("name") ) diff --git a/coldfront/core/resource/models.py b/coldfront/core/resource/models.py index d2a5531022..1cb1a3b964 100644 --- a/coldfront/core/resource/models.py +++ b/coldfront/core/resource/models.py @@ -230,7 +230,7 @@ def get_ondemand_status(self): return None def __str__(self): - return "%s (%s)" % (self.name, self.resource_type.name) + return f"{self.name} ({self.resource_type.name})" def natural_key(self): return [self.name] @@ -255,19 +255,19 @@ def clean(self): expected_value_type = self.resource_attribute_type.attribute_type.name.strip() if expected_value_type == "Int" and not self.value.isdigit(): - raise ValidationError('Invalid Value "%s". Value must be an integer.' % (self.value)) + raise ValidationError(f'Invalid Value "{self.value}". Value must be an integer.') elif expected_value_type == "Active/Inactive" and self.value not in ["Active", "Inactive"]: - raise ValidationError('Invalid Value "%s". Allowed inputs are "Active" or "Inactive".' % (self.value)) + raise ValidationError(f'Invalid Value "{self.value}". Allowed inputs are "Active" or "Inactive".') elif expected_value_type == "Public/Private" and self.value not in ["Public", "Private"]: - raise ValidationError('Invalid Value "%s". Allowed inputs are "Public" or "Private".' % (self.value)) + raise ValidationError(f'Invalid Value "{self.value}". Allowed inputs are "Public" or "Private".') elif expected_value_type == "Date": try: datetime.strptime(self.value.strip(), "%m/%d/%Y") except ValueError: - raise ValidationError('Invalid Value "%s". Date must be in format MM/DD/YYYY' % (self.value)) + raise ValidationError(f'Invalid Value "{self.value}". Date must be in format MM/DD/YYYY') def __str__(self): - return "%s: %s (%s)" % (self.resource_attribute_type, self.value, self.resource) + return f"{self.resource_attribute_type}: {self.value} ({self.resource})" def typed_value(self): """ diff --git a/coldfront/core/resource/views.py b/coldfront/core/resource/views.py index 7f9e4aca3a..1aafe614a5 100644 --- a/coldfront/core/resource/views.py +++ b/coldfront/core/resource/views.py @@ -185,7 +185,7 @@ def post(self, request, *args, **kwargs): resource_attribute = ResourceAttribute.objects.get(pk=form_data["pk"]) resource_attribute.delete() - messages.success(request, "Deleted {} attributes from resource.".format(attributes_deleted_count)) + messages.success(request, f"Deleted {attributes_deleted_count} attributes from resource.") else: for error in formset.errors: messages.error(request, error) @@ -288,9 +288,9 @@ def get_context_data(self, **kwargs): if value: if isinstance(value, list): for ele in value: - filter_parameters += "{}={}&".format(key, ele) + filter_parameters += f"{key}={ele}&" else: - filter_parameters += "{}={}&".format(key, value) + filter_parameters += f"{key}={value}&" context["resource_search_form"] = resource_search_form else: filter_parameters = None @@ -299,7 +299,8 @@ def get_context_data(self, **kwargs): order_by = self.request.GET.get("order_by") if order_by: direction = self.request.GET.get("direction") - filter_parameters_with_order_by = filter_parameters + "order_by=%s&direction=%s&" % (order_by, direction) + filter_parameters_string = "" if not filter_parameters else filter_parameters + filter_parameters_with_order_by = filter_parameters_string + f"order_by={order_by}&direction={direction}&" else: filter_parameters_with_order_by = filter_parameters diff --git a/coldfront/core/test_helpers/decorators.py b/coldfront/core/test_helpers/decorators.py index 41ec96259f..9a7d5c79bd 100644 --- a/coldfront/core/test_helpers/decorators.py +++ b/coldfront/core/test_helpers/decorators.py @@ -11,7 +11,7 @@ def _skipUnlessEnvDefined(varname, reason=None): skip = varname not in os.environ if skip and reason is None: - reason = "Automatically skipped. {} is not defined".format(varname) + reason = f"Automatically skipped. {varname} is not defined" return functools.partial(unittest.skipIf, skip, reason) diff --git a/coldfront/core/test_helpers/factories.py b/coldfront/core/test_helpers/factories.py index b852110095..42750beeec 100644 --- a/coldfront/core/test_helpers/factories.py +++ b/coldfront/core/test_helpers/factories.py @@ -86,7 +86,7 @@ class Meta: last_name = factory.Faker("last_name") # username = factory.Faker('username') username = factory.LazyAttribute(lambda o: f"{o.first_name}{o.last_name}") - email = factory.LazyAttribute(lambda o: "%s@example.com" % o.username) + email = factory.LazyAttribute(lambda o: f"{o.username}@example.com") class UserProfileFactory(DjangoModelFactory): diff --git a/coldfront/core/utils/common.py b/coldfront/core/utils/common.py index 9fd84a2de3..4ea3b0ae34 100644 --- a/coldfront/core/utils/common.py +++ b/coldfront/core/utils/common.py @@ -24,7 +24,7 @@ def import_from_settings(attr, *args): return getattr(settings, attr, args[0]) return getattr(settings, attr) except AttributeError: - raise ImproperlyConfigured("Setting {0} not found".format(attr)) + raise ImproperlyConfigured(f"Setting {attr} not found") def get_domain_url(request): diff --git a/coldfront/core/utils/mail.py b/coldfront/core/utils/mail.py index 6e4d442ed1..1645aabe33 100644 --- a/coldfront/core/utils/mail.py +++ b/coldfront/core/utils/mail.py @@ -148,8 +148,8 @@ def send_allocation_eula_customer_email( ctx = email_template_context() ctx["resource"] = allocation_obj.get_parent_resource ctx["url"] = url - ctx["allocation_user"] = "{} {} ({})".format( - allocation_user.user.first_name, allocation_user.user.last_name, allocation_user.user.username + ctx["allocation_user"] = ( + f"{allocation_user.user.first_name} {allocation_user.user.last_name} ({allocation_user.user.username})" ) if include_eula: ctx["eula"] = allocation_obj.get_eula() diff --git a/coldfront/core/utils/mixins/views.py b/coldfront/core/utils/mixins/views.py index 105749241c..ca06e4a741 100644 --- a/coldfront/core/utils/mixins/views.py +++ b/coldfront/core/utils/mixins/views.py @@ -32,7 +32,7 @@ def to_snake(string): app_label = self.model._meta.app_label model_name = self.model.__name__ - return ["{}/{}{}.html".format(app_label, to_snake(model_name), self.template_name_suffix)] + return [f"{app_label}/{to_snake(model_name)}{self.template_name_suffix}.html"] class ProjectInContextMixin: diff --git a/coldfront/plugins/freeipa/management/commands/freeipa_check.py b/coldfront/plugins/freeipa/management/commands/freeipa_check.py index 165b033127..6ef3afbc61 100644 --- a/coldfront/plugins/freeipa/management/commands/freeipa_check.py +++ b/coldfront/plugins/freeipa/management/commands/freeipa_check.py @@ -44,7 +44,7 @@ def add_arguments(self, parser): def writerow(self, row): try: - self.stdout.write("{0: <12}{1: <20}{2: <30}{3}".format(*row)) + self.stdout.write(f"{row[0]:<20}{row[1]:<15}{row[2]}") except BrokenPipeError: devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) diff --git a/coldfront/plugins/freeipa/management/commands/freeipa_expire_users.py b/coldfront/plugins/freeipa/management/commands/freeipa_expire_users.py index 3bd0bcdd09..6029e87a81 100644 --- a/coldfront/plugins/freeipa/management/commands/freeipa_expire_users.py +++ b/coldfront/plugins/freeipa/management/commands/freeipa_expire_users.py @@ -29,7 +29,7 @@ def add_arguments(self, parser): def writerow(self, row): try: - self.stdout.write("{0: <20}{1: <15}{2}".format(*row)) + self.stdout.write(f"{row[0]:<20}{row[1]:<15}{row[2]}") except BrokenPipeError: devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) diff --git a/coldfront/plugins/freeipa/search.py b/coldfront/plugins/freeipa/search.py index 12da2f9cab..d34a3da3e9 100644 --- a/coldfront/plugins/freeipa/search.py +++ b/coldfront/plugins/freeipa/search.py @@ -25,7 +25,7 @@ def __init__(self, user_search_string, search_by): self.FREEIPA_USER_SEARCH_BASE = import_from_settings("FREEIPA_USER_SEARCH_BASE", "cn=users,cn=accounts") self.FREEIPA_KTNAME = import_from_settings("FREEIPA_KTNAME", "") - self.server = Server("ldap://{}".format(self.FREEIPA_SERVER), use_ssl=True, connect_timeout=1) + self.server = Server(f"ldap://{self.FREEIPA_SERVER}", use_ssl=True, connect_timeout=1) if len(self.FREEIPA_KTNAME) > 0: logger.info("Kerberos bind enabled: %s", self.FREEIPA_KTNAME) # kerberos SASL/GSSAPI bind @@ -36,7 +36,7 @@ def __init__(self, user_search_string, search_by): self.conn = Connection(self.server, auto_bind=True) if not self.conn.bind(): - raise ImproperlyConfigured("Failed to bind to LDAP server: {}".format(self.conn.result)) + raise ImproperlyConfigured(f"Failed to bind to LDAP server: {self.conn.result}") else: logger.info("LDAP bind successful: %s", self.conn.extend.standard.who_am_i()) diff --git a/coldfront/plugins/freeipa/utils.py b/coldfront/plugins/freeipa/utils.py index 0893bf9662..c76eabfc97 100644 --- a/coldfront/plugins/freeipa/utils.py +++ b/coldfront/plugins/freeipa/utils.py @@ -36,7 +36,7 @@ class NotMemberError(ApiError): api.Backend.rpcclient.connect() except Exception as e: logger.error("Failed to initialze FreeIPA lib: %s", e) - raise ImproperlyConfigured("Failed to initialze FreeIPA: {0}".format(e)) + raise ImproperlyConfigured(f"Failed to initialze FreeIPA: {e}") def check_ipa_group_error(res): diff --git a/coldfront/plugins/iquota/utils.py b/coldfront/plugins/iquota/utils.py index 9b63bcc3a9..8fb458664b 100644 --- a/coldfront/plugins/iquota/utils.py +++ b/coldfront/plugins/iquota/utils.py @@ -49,14 +49,14 @@ def get_user_quota(self): token = self.gssclient_token() headers = {"Authorization": "Negotiate " + token} - url = "https://{}:{}/quota?user={}".format(self.IQUOTA_API_HOST, self.IQUOTA_API_PORT, self.username) + url = f"https://{self.IQUOTA_API_HOST}:{self.IQUOTA_API_PORT}/quota?user={self.username}" r = requests.get(url, headers=headers, verify=self.IQUOTA_CA_CERT) try: usage = r.json()[0] except KeyError: - raise MissingQuotaError("Missing user quota for username: %s" % (self.username)) + raise MissingQuotaError(f"Missing user quota for username: {self.username}") else: user_used = usage["used"] user_limit = usage["soft_limit"] @@ -77,7 +77,7 @@ def _get_group_quota(self, group): headers = {"Authorization": "Negotiate " + token} - url = "https://{}:{}/quota?group={}".format(self.IQUOTA_API_HOST, self.IQUOTA_API_PORT, group) + url = f"https://{self.IQUOTA_API_HOST}:{self.IQUOTA_API_PORT}/quota?group={group}" r = requests.get(url, headers=headers, verify=self.IQUOTA_CA_CERT) diff --git a/coldfront/plugins/mokey_oidc/auth.py b/coldfront/plugins/mokey_oidc/auth.py index b8d5d77e7c..1316469494 100644 --- a/coldfront/plugins/mokey_oidc/auth.py +++ b/coldfront/plugins/mokey_oidc/auth.py @@ -93,7 +93,7 @@ def filter_users_by_claims(self, claims): return self.UserModel.objects.none() def verify_claims(self, claims): - verified = super(OIDCMokeyAuthenticationBackend, self).verify_claims(claims) + verified = super().verify_claims(claims) if len(ALLOWED_GROUPS) == 0 and len(DENY_GROUPS) == 0: return verified and True diff --git a/coldfront/plugins/slurm/associations.py b/coldfront/plugins/slurm/associations.py index 28b74fde92..d1c519b5db 100644 --- a/coldfront/plugins/slurm/associations.py +++ b/coldfront/plugins/slurm/associations.py @@ -77,7 +77,7 @@ def new_from_stream(stream): parts = line.split(":") name = re.sub(r"^Cluster - ", "", parts[0]).strip("\n'") if len(name) == 0: - raise (SlurmParserError("Cluster name not found for line: {}".format(line))) + raise (SlurmParserError(f"Cluster name not found for line: {line}")) cluster = SlurmCluster(name) cluster.specs += parts[1:] elif re.match("^Account - '[^']+'", line): @@ -88,11 +88,11 @@ def new_from_stream(stream): if parent == "root": cluster.accounts["root"] = SlurmAccount("root") if not parent: - raise (SlurmParserError("Parent name not found for line: {}".format(line))) + raise (SlurmParserError(f"Parent name not found for line: {line}")) elif re.match("^User - '[^']+'", line): user = SlurmUser.new_from_sacctmgr(line) if not parent: - raise (SlurmParserError("Found user record without Parent for line: {}".format(line))) + raise (SlurmParserError(f"Found user record without Parent for line: {line}")) account = cluster.accounts[parent] account.add_user(user) cluster.accounts[parent] = account @@ -109,7 +109,7 @@ def new_from_resource(resource): specs = resource.get_attribute_list(SLURM_SPECS_ATTRIBUTE_NAME) user_specs = resource.get_attribute_list(SLURM_USER_SPECS_ATTRIBUTE_NAME) if not name: - raise (SlurmError("Resource {} missing slurm_cluster".format(resource))) + raise (SlurmError(f"Resource {resource} missing slurm_cluster")) cluster = SlurmCluster(name, specs) @@ -143,13 +143,10 @@ def add_allocation(self, allocation, specs=None, user_specs=None): self.accounts[name] = account def write(self, out): - self._write(out, "# ColdFront Allocation Slurm associations dump {}\n".format(datetime.datetime.now().date())) + self._write(out, f"# ColdFront Allocation Slurm associations dump {datetime.datetime.now().date()}\n") self._write( out, - "Cluster - '{}':{}\n".format( - self.name, - self.format_specs(), - ), + f"Cluster - '{self.name}':{self.format_specs()}\n", ) if "root" in self.accounts: self.accounts["root"].write(out) @@ -176,12 +173,12 @@ def new_from_sacctmgr(line): """Create a new SlurmAccount by parsing a line from sacctmgr dump. For example: Account - 'physics':Description='physics group':Organization='cas':Fairshare=100""" if not re.match("^Account - '[^']+'", line): - raise (SlurmParserError('Invalid format. Must start with "Account" for line: {}'.format(line))) + raise (SlurmParserError(f'Invalid format. Must start with "Account" for line: {line}')) parts = line.split(":") name = re.sub(r"^Account - ", "", parts[0]).strip("\n'") if len(name) == 0: - raise (SlurmParserError("Cluster name not found for line: {}".format(line))) + raise (SlurmParserError(f"Cluster name not found for line: {line}")) return SlurmAccount(name, specs=parts[1:]) @@ -195,7 +192,7 @@ def add_allocation(self, allocation, user_specs=None): name = "root" if name != self.name: - raise (SlurmError("Allocation {} slurm_account_name does not match {}".format(allocation, self.name))) + raise (SlurmError(f"Allocation {allocation} slurm_account_name does not match {self.name}")) self.specs += allocation.get_attribute_list(SLURM_SPECS_ATTRIBUTE_NAME) @@ -218,14 +215,11 @@ def write(self, out): if self.name != "root": self._write( out, - "Account - '{}':{}\n".format( - self.name, - self.format_specs(), - ), + f"Account - '{self.name}':{self.format_specs()}\n", ) def write_users(self, out): - self._write(out, "Parent - '{}'\n".format(self.name)) + self._write(out, f"Parent - '{self.name}'\n") for uid, user in self.users.items(): user.write(out) @@ -236,20 +230,17 @@ def new_from_sacctmgr(line): """Create a new SlurmUser by parsing a line from sacctmgr dump. For example: User - 'jane':DefaultAccount='physics':Fairshare=Parent:QOS='general-compute'""" if not re.match("^User - '[^']+'", line): - raise (SlurmParserError('Invalid format. Must start with "User" for line: {}'.format(line))) + raise (SlurmParserError(f'Invalid format. Must start with "User" for line: {line}')) parts = line.split(":") name = re.sub(r"^User - ", "", parts[0]).strip("\n'") if len(name) == 0: - raise (SlurmParserError("User name not found for line: {}".format(line))) + raise (SlurmParserError(f"User name not found for line: {line}")) return SlurmUser(name, specs=parts[1:]) def write(self, out): self._write( out, - "User - '{}':{}\n".format( - self.name, - self.format_specs(), - ), + f"User - '{self.name}':{self.format_specs()}\n", ) diff --git a/coldfront/plugins/slurm/management/commands/slurm_dump.py b/coldfront/plugins/slurm/management/commands/slurm_dump.py index 5e590f8628..a9d5ee58a5 100644 --- a/coldfront/plugins/slurm/management/commands/slurm_dump.py +++ b/coldfront/plugins/slurm/management/commands/slurm_dump.py @@ -53,5 +53,5 @@ def handle(self, *args, **options): cluster.write(self.stdout) continue - with open(os.path.join(out_dir, "{}.cfg".format(cluster.name)), "w") as fh: + with open(os.path.join(out_dir, f"{cluster.name}.cfg"), "w") as fh: cluster.write(fh) diff --git a/coldfront/plugins/slurm/tests/test_associations.py b/coldfront/plugins/slurm/tests/test_associations.py index 7d97ea55ef..5a20689b47 100644 --- a/coldfront/plugins/slurm/tests/test_associations.py +++ b/coldfront/plugins/slurm/tests/test_associations.py @@ -21,7 +21,7 @@ def setUpClass(cls): call_command("add_default_project_choices") call_command("add_default_allocation_choices") call_command("add_default_publication_sources") - super(AssociationTest, cls).setUpClass() + super().setUpClass() def test_allocations_to_slurm(self): resource = Resource.objects.get(name="University HPC") diff --git a/coldfront/plugins/slurm/utils.py b/coldfront/plugins/slurm/utils.py index 7f8bf9db48..a72eae6f18 100644 --- a/coldfront/plugins/slurm/utils.py +++ b/coldfront/plugins/slurm/utils.py @@ -44,7 +44,7 @@ def _run_slurm_cmd(cmd, noop=True): return try: - result = subprocess.run(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) + result = subprocess.run(shlex.split(cmd), check=True, capture_output=True) except subprocess.CalledProcessError as e: if "Nothing deleted" in str(e.stdout): # We tried to delete something that didn't exist. Don't throw error @@ -56,7 +56,7 @@ def _run_slurm_cmd(cmd, noop=True): return e.stdout logger.error("Slurm command failed: %s", cmd) - err_msg = "return_value={} stdout={} stderr={}".format(e.returncode, e.stdout, e.stderr) + err_msg = f"return_value={e.returncode} stdout={e.stdout} stderr={e.stderr}" raise SlurmError(err_msg) logger.debug("Slurm cmd: %s", cmd) diff --git a/coldfront/plugins/system_monitor/utils.py b/coldfront/plugins/system_monitor/utils.py index 98ec886c19..0361adf5e7 100644 --- a/coldfront/plugins/system_monitor/utils.py +++ b/coldfront/plugins/system_monitor/utils.py @@ -103,12 +103,13 @@ def parse_html_using_beautiful_soup(self): utilized_percent = round(processors_utilized[0] / processors_utilized[1] * 1000) / 10 free_percent = round(free / processors_utilized[1] * 1000) / 10 - utilized_label = "Processors Utilized: %s (%s%%)" % (processors_utilized[0], utilized_percent) - free_label = "Processors Free: %s (%s%%)" % (free, free_percent) + utilized_label = f"Processors Utilized: {processors_utilized[0]} ({utilized_percent}%)" + free_label = f"Processors Free: {free} ({free_percent}%)" + utilized_value = processors_utilized[0] free_value = free - running_label = "Running: %s" % (jobs[0]) - queued_label = "Queued: %s" % (jobs[1]) + running_label = f"Running: {jobs[0]}" + queued_label = f"Queued: {jobs[1]}" running_value = job_numbers[0] queued_value = job_numbers[1] except Exception: diff --git a/coldfront/plugins/xdmod/utils.py b/coldfront/plugins/xdmod/utils.py index 7922ad325e..c8e3f14885 100644 --- a/coldfront/plugins/xdmod/utils.py +++ b/coldfront/plugins/xdmod/utils.py @@ -53,9 +53,9 @@ def xdmod_fetch_total_cpu_hours(start, end, account, resources=None, statistics= if resources is None: resources = [] - url = "{}{}".format(XDMOD_API_URL, _ENDPOINT_CORE_HOURS) + url = f"{XDMOD_API_URL}{_ENDPOINT_CORE_HOURS}" payload = _DEFAULT_PARAMS - payload["pi_filter"] = '"{}"'.format(account) + payload["pi_filter"] = f'"{account}"' payload["resource_filter"] = '"{}"'.format(",".join(resources)) payload["start_date"] = start payload["end_date"] = end @@ -72,7 +72,7 @@ def xdmod_fetch_total_cpu_hours(start, end, account, resources=None, statistics= error = r.json() # XXX fix me. Here we assume any json response is bad as we're # expecting xml but XDMoD should just return json always. - raise XdmodNotFoundError("Got json response but expected XML: {}".format(error)) + raise XdmodNotFoundError(f"Got json response but expected XML: {error}") except json.decoder.JSONDecodeError: pass except requests.exceptions.JSONDecodeError: @@ -81,11 +81,11 @@ def xdmod_fetch_total_cpu_hours(start, end, account, resources=None, statistics= try: root = ET.fromstring(r.text) except ET.ParserError as e: - raise XdmodError("Invalid XML data returned from XDMoD API: {}".format(e)) + raise XdmodError(f"Invalid XML data returned from XDMoD API: {e}") rows = root.find("rows") if len(rows) != 1: - raise XdmodNotFoundError("Rows not found for {} - {}".format(account, resources)) + raise XdmodNotFoundError(f"Rows not found for {account} - {resources}") cells = rows.find("row").findall("cell") if len(cells) != 2: @@ -103,9 +103,9 @@ def xdmod_fetch_total_storage(start, end, account, resources=None, statistics="p payload_end = end if payload_end is None: payload_end = "2099-01-01" - url = "{}{}".format(XDMOD_API_URL, _ENDPOINT_CORE_HOURS) + url = f"{XDMOD_API_URL}{_ENDPOINT_CORE_HOURS}" payload = _DEFAULT_PARAMS - payload["pi_filter"] = '"{}"'.format(account) + payload["pi_filter"] = f'"{account}"' payload["resource_filter"] = "{}".format(",".join(resources)) payload["start_date"] = start payload["end_date"] = payload_end @@ -121,11 +121,11 @@ def xdmod_fetch_total_storage(start, end, account, resources=None, statistics="p try: root = ET.fromstring(r.text) except ET.ParserError as e: - raise XdmodError("Invalid XML data returned from XDMoD API: {}".format(e)) + raise XdmodError(f"Invalid XML data returned from XDMoD API: {e}") rows = root.find("rows") if len(rows) != 1: - raise XdmodNotFoundError("Rows not found for {} - {}".format(account, resources)) + raise XdmodNotFoundError(f"Rows not found for {account} - {resources}") cells = rows.find("row").findall("cell") if len(cells) != 2: @@ -140,7 +140,7 @@ def xdmod_fetch_cloud_core_time(start, end, project, resources=None): if resources is None: resources = [] - url = "{}{}".format(XDMOD_API_URL, _ENDPOINT_CORE_HOURS) + url = f"{XDMOD_API_URL}{_ENDPOINT_CORE_HOURS}" payload = _DEFAULT_PARAMS payload["project_filter"] = project payload["resource_filter"] = '"{}"'.format(",".join(resources)) @@ -159,18 +159,18 @@ def xdmod_fetch_cloud_core_time(start, end, project, resources=None): error = r.json() # XXX fix me. Here we assume any json response is bad as we're # expecting xml but XDMoD should just return json always. - raise XdmodNotFoundError("Got json response but expected XML: {}".format(error)) + raise XdmodNotFoundError(f"Got json response but expected XML: {error}") except json.decoder.JSONDecodeError: pass try: root = ET.fromstring(r.text) except ET.ParserError as e: - raise XdmodError("Invalid XML data returned from XDMoD API: {}".format(e)) + raise XdmodError(f"Invalid XML data returned from XDMoD API: {e}") rows = root.find("rows") if len(rows) != 1: - raise XdmodNotFoundError("Rows not found for {} - {}".format(project, resources)) + raise XdmodNotFoundError(f"Rows not found for {project} - {resources}") cells = rows.find("row").findall("cell") if len(cells) != 2: diff --git a/pyproject.toml b/pyproject.toml index 33bf9873f8..a20069512c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,7 +107,7 @@ indent-width = 4 target-version = "py312" [tool.ruff.lint] -select = ["E4", "E7", "E9", "F", "I"] +select = ["E4", "E7", "E9", "F", "I", "UP"] [tool.ruff.format] indent-style = "space"