From 26ae0f3460f29116e0c083d57eee9f33763237ea Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Mon, 5 Feb 2024 20:05:19 +0530 Subject: [PATCH] fix: ruff fixes Signed-off-by: Akhil Narang --- .github/helper/ci.py | 2 +- .github/helper/documentation.py | 15 +- .github/helper/roulette.py | 8 +- .github/helper/translation.py | 34 +++-- frappe/__init__.py | 16 +- frappe/auth.py | 2 +- .../assignment_rule/test_assignment_rule.py | 2 +- frappe/build.py | 3 - frappe/commands/site.py | 2 +- frappe/commands/translate.py | 4 +- frappe/commands/utils.py | 4 +- frappe/contacts/doctype/address/address.py | 9 +- frappe/contacts/doctype/contact/contact.py | 8 +- .../addresses_and_contacts.py | 1 - .../core/doctype/activity_log/activity_log.py | 2 +- .../core/doctype/data_import/data_import.py | 2 +- frappe/core/doctype/data_import/importer.py | 11 +- frappe/core/doctype/doctype/doctype.py | 12 +- .../core/doctype/error_log/test_error_log.py | 16 +- frappe/core/doctype/file/file.py | 2 +- frappe/core/doctype/page/page.py | 11 +- frappe/core/doctype/report/report.py | 4 +- frappe/core/doctype/report/test_report.py | 102 +++++++++---- .../doctype/server_script/server_script.py | 4 +- .../server_script/test_server_script.py | 4 +- frappe/core/doctype/user/user.py | 9 +- .../permitted_documents_for_user.py | 6 +- .../doctype/customize_form/customize_form.py | 6 +- .../audit_system_hooks/audit_system_hooks.py | 2 +- frappe/database/database.py | 14 +- frappe/database/mariadb/database.py | 28 ++-- frappe/database/mariadb/setup_db.py | 5 +- frappe/database/postgres/database.py | 27 ++-- frappe/database/postgres/schema.py | 10 +- frappe/database/query.py | 22 +-- frappe/database/schema.py | 4 +- frappe/defaults.py | 10 +- frappe/deferred_insert.py | 2 +- frappe/desk/desktop.py | 10 +- frappe/desk/doctype/dashboard/dashboard.py | 4 +- .../dashboard_chart/dashboard_chart.py | 14 +- frappe/desk/doctype/event/event.py | 4 +- .../desk/doctype/kanban_board/kanban_board.py | 4 +- .../desk/doctype/number_card/number_card.py | 10 +- frappe/desk/form/linked_with.py | 2 +- frappe/desk/form/load.py | 14 +- frappe/desk/form/utils.py | 4 +- frappe/desk/leaderboard.py | 4 +- frappe/desk/notifications.py | 2 +- frappe/desk/query_report.py | 12 +- frappe/desk/reportview.py | 10 +- .../auto_email_report/auto_email_report.py | 2 +- .../doctype/email_account/email_account.py | 84 ++++++++--- .../email_account/test_email_account.py | 12 +- .../email/doctype/email_group/email_group.py | 2 +- frappe/frappeclient.py | 2 +- frappe/gettext/extractors/navbar.py | 4 +- frappe/installer.py | 4 +- .../dropbox_settings/dropbox_settings.py | 2 +- .../ldap_settings/test_ldap_settings.py | 4 +- .../frappe_providers/frappecloud.py | 6 +- frappe/integrations/google_oauth.py | 2 +- frappe/integrations/offsite_backup_utils.py | 8 +- frappe/integrations/utils.py | 2 +- frappe/model/base_document.py | 8 +- frappe/model/db_query.py | 17 +-- frappe/model/delete_doc.py | 12 +- frappe/model/document.py | 8 +- frappe/model/meta.py | 8 +- frappe/model/naming.py | 8 +- frappe/model/rename_doc.py | 2 +- frappe/model/utils/__init__.py | 8 +- frappe/model/utils/rename_field.py | 10 +- frappe/modules/import_file.py | 8 +- frappe/parallel_test_runner.py | 2 +- .../delete_duplicate_user_permissions.py | 4 +- .../v11_0/update_list_user_settings.py | 4 +- .../move_email_and_phone_to_child_table.py | 1 - .../v12_0/replace_null_values_in_tables.py | 2 +- .../update_date_filters_in_user_settings.py | 6 +- frappe/permissions.py | 2 +- frappe/recorder.py | 2 +- .../energy_point_log/energy_point_log.py | 4 +- .../energy_point_rule/energy_point_rule.py | 2 +- frappe/test_runner.py | 4 +- frappe/tests/test_api.py | 4 +- frappe/tests/test_caching.py | 6 +- frappe/tests/test_db.py | 5 +- frappe/tests/test_db_query.py | 141 ++++++++++++++---- frappe/tests/test_oauth20.py | 2 +- frappe/tests/test_patches.py | 2 +- frappe/tests/test_perf.py | 2 +- frappe/tests/test_query_report.py | 5 +- frappe/tests/test_recorder.py | 4 +- frappe/tests/test_safe_exec.py | 2 +- frappe/tests/test_translate.py | 6 +- frappe/tests/test_twofactor.py | 2 +- frappe/tests/test_utils.py | 114 ++++++++++---- frappe/tests/utils.py | 4 +- frappe/translate.py | 7 +- frappe/twofactor.py | 1 - frappe/utils/__init__.py | 8 +- frappe/utils/background_jobs.py | 4 +- frappe/utils/backups.py | 7 +- frappe/utils/boilerplate.py | 4 +- frappe/utils/change_log.py | 4 +- frappe/utils/csvutils.py | 2 +- frappe/utils/dashboard.py | 3 +- frappe/utils/data.py | 22 +-- frappe/utils/dateutils.py | 5 +- frappe/utils/global_search.py | 2 +- frappe/utils/image.py | 2 +- frappe/utils/jinja_globals.py | 2 +- frappe/utils/make_random.py | 12 +- frappe/utils/print_format.py | 2 +- frappe/utils/redis_wrapper.py | 2 +- frappe/utils/response.py | 2 +- frappe/utils/safe_exec.py | 20 ++- frappe/utils/typing_validations.py | 16 +- .../doctype/blog_post/test_blog_post.py | 2 +- .../website_settings/website_settings.py | 2 +- .../website/page_renderers/template_page.py | 4 +- .../website_analytics/website_analytics.py | 18 +-- frappe/website/router.py | 2 +- frappe/workflow/doctype/workflow/workflow.py | 10 +- .../workflow_action/workflow_action.py | 6 +- frappe/www/list.py | 6 +- frappe/www/printview.py | 2 +- 128 files changed, 696 insertions(+), 557 deletions(-) diff --git a/.github/helper/ci.py b/.github/helper/ci.py index 10bafb3dc5..9c4e1379bb 100644 --- a/.github/helper/ci.py +++ b/.github/helper/ci.py @@ -1,8 +1,8 @@ # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See LICENSE +import json import os from pathlib import Path -import json STANDARD_INCLUSIONS = ["*.py"] diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py index b541583fd6..7eb209cbde 100644 --- a/.github/helper/documentation.py +++ b/.github/helper/documentation.py @@ -1,7 +1,7 @@ import sys -import requests from urllib.parse import urlparse +import requests WEBSITE_REPOS = [ "erpnext_com", @@ -36,11 +36,7 @@ def is_documentation_link(word: str) -> bool: def contains_documentation_link(body: str) -> bool: - return any( - is_documentation_link(word) - for line in body.splitlines() - for word in line.split() - ) + return any(is_documentation_link(word) for line in body.splitlines() for word in line.split()) def check_pull_request(number: str) -> "tuple[int, str]": @@ -53,12 +49,7 @@ def check_pull_request(number: str) -> "tuple[int, str]": head_sha = (payload.get("head") or {}).get("sha") body = (payload.get("body") or "").lower() - if ( - not title.startswith("feat") - or not head_sha - or "no-docs" in body - or "backport" in body - ): + if not title.startswith("feat") or not head_sha or "no-docs" in body or "backport" in body: return 0, "Skipping documentation checks... 🏃" if contains_documentation_link(body): diff --git a/.github/helper/roulette.py b/.github/helper/roulette.py index ebca901c95..121b9ff0d6 100644 --- a/.github/helper/roulette.py +++ b/.github/helper/roulette.py @@ -6,11 +6,11 @@ import subprocess import sys import time import urllib.request -from functools import lru_cache +from functools import cache from urllib.error import HTTPError -@lru_cache(maxsize=None) +@cache def fetch_pr_data(pr_number, repo, endpoint=""): api_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}" @@ -83,9 +83,7 @@ def is_ci(file): def is_frontend_code(file): - return file.lower().endswith( - (".css", ".scss", ".less", ".sass", ".styl", ".js", ".ts", ".vue", ".html") - ) + return file.lower().endswith((".css", ".scss", ".less", ".sass", ".styl", ".js", ".ts", ".vue", ".html")) def is_docs(file): diff --git a/.github/helper/translation.py b/.github/helper/translation.py index 72f661d3e1..96a319f97e 100644 --- a/.github/helper/translation.py +++ b/.github/helper/translation.py @@ -2,7 +2,9 @@ import re import sys errors_encounter = 0 -pattern = re.compile(r"_\(([\"']{,3})(?P((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P((?!\11).)*)\11)*)*\)") +pattern = re.compile( + r"_\(([\"']{,3})(?P((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P((?!\5).)*)\5)*(\s*,(\s*?.*?\n*?)*(,\s*([\"'])(?P((?!\11).)*)\11)*)*\)" +) words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]") start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}") f_string_pattern = re.compile(r"_\(f[\"']") @@ -10,44 +12,50 @@ starts_with_f_pattern = re.compile(r"_\(f") # skip first argument files = sys.argv[1:] -files_to_scan = [_file for _file in files if _file.endswith(('.py', '.js'))] +files_to_scan = [_file for _file in files if _file.endswith((".py", ".js"))] for _file in files_to_scan: - with open(_file, 'r') as f: - print(f'Checking: {_file}') + with open(_file) as f: + print(f"Checking: {_file}") file_lines = f.readlines() for line_number, line in enumerate(file_lines, 1): - if 'frappe-lint: disable-translate' in line: + if "frappe-lint: disable-translate" in line: continue if start_matches := start_pattern.search(line): if starts_with_f := starts_with_f_pattern.search(line): if has_f_string := f_string_pattern.search(line): errors_encounter += 1 - print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}') + print( + f"\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}" + ) continue match = pattern.search(line) error_found = False - if not match and line.endswith((',\n', '[\n')): + if not match and line.endswith((",\n", "[\n")): # concat remaining text to validate multiline pattern - line = "".join(file_lines[line_number - 1:]) - line = line[start_matches.start() + 1:] + line = "".join(file_lines[line_number - 1 :]) + line = line[start_matches.start() + 1 :] match = pattern.match(line) if not match: error_found = True - print(f'\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}') + print(f"\nTranslation syntax error at line number {line_number}\n{line.strip()[:100]}") if not error_found and not words_pattern.search(line): error_found = True - print(f'\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}') + print( + f"\nTranslation is useless because it has no words at line number {line_number}\n{line.strip()[:100]}" + ) if error_found: errors_encounter += 1 if errors_encounter > 0: - print('\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.') + print( + '\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.' + ) sys.exit(1) else: - print('\nGood To Go!') + print("\nGood To Go!") diff --git a/frappe/__init__.py b/frappe/__init__.py index cca8f12198..ff953cce26 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -152,12 +152,12 @@ class _LazyTranslate: return self.value def __add__(self, other): - if isinstance(other, (str, _LazyTranslate)): + if isinstance(other, str | _LazyTranslate): return self.value + str(other) raise NotImplementedError def __radd__(self, other): - if isinstance(other, (str, _LazyTranslate)): + if isinstance(other, str | _LazyTranslate): return str(other) + self.value return NotImplementedError @@ -1300,7 +1300,7 @@ def get_cached_value(doctype: str, name: str, fieldname: str = "name", as_dict: values = [doc.get(f) for f in fieldname] if as_dict: - return _dict(zip(fieldname, values)) + return _dict(zip(fieldname, values, strict=False)) return values @@ -1644,7 +1644,7 @@ def _load_app_hooks(app_name: str | None = None): raise def _is_valid_hook(obj): - return not isinstance(obj, (types.ModuleType, types.FunctionType, type)) + return not isinstance(obj, types.ModuleType | types.FunctionType | type) for key, value in inspect.getmembers(app_hooks, predicate=_is_valid_hook): if not key.startswith("_"): @@ -1904,7 +1904,7 @@ def copy_doc(doc: "Document", ignore_no_copy: bool = True) -> "Document": if not ignore_no_copy: remove_no_copy_fields(newdoc) - for i, d in enumerate(newdoc.get_all_children()): + for d in newdoc.get_all_children(): d.set("__islocal", 1) for fieldname in fields_to_clear: @@ -2493,7 +2493,7 @@ def mock(type, size=1, locale="en"): if type not in dir(fake): raise ValueError("Not a valid mock type.") else: - for i in range(size): + for _ in range(size): data = getattr(fake, type)() results.append(data) @@ -2507,7 +2507,7 @@ def validate_and_sanitize_search_inputs(fn): def wrapper(*args, **kwargs): from frappe.desk.search import sanitize_searchfield - kwargs.update(dict(zip(fn.__code__.co_varnames, args))) + kwargs.update(dict(zip(fn.__code__.co_varnames, args, strict=False))) sanitize_searchfield(kwargs["searchfield"]) kwargs["start"] = cint(kwargs["start"]) kwargs["page_len"] = cint(kwargs["page_len"]) @@ -2520,7 +2520,7 @@ def validate_and_sanitize_search_inputs(fn): return wrapper -from frappe.utils.error import log_error # noqa: backward compatibility +from frappe.utils.error import log_error # noqa if _tune_gc: # generational GC gets triggered after certain allocs (g0) which is 700 by default. diff --git a/frappe/auth.py b/frappe/auth.py index ae19e0558b..ee8ec24104 100644 --- a/frappe/auth.py +++ b/frappe/auth.py @@ -376,7 +376,7 @@ class CookieManager: } def delete_cookie(self, to_delete): - if not isinstance(to_delete, (list, tuple)): + if not isinstance(to_delete, list | tuple): to_delete = [to_delete] self.to_delete.extend(to_delete) diff --git a/frappe/automation/doctype/assignment_rule/test_assignment_rule.py b/frappe/automation/doctype/assignment_rule/test_assignment_rule.py index ed5fca7902..da123840aa 100644 --- a/frappe/automation/doctype/assignment_rule/test_assignment_rule.py +++ b/frappe/automation/doctype/assignment_rule/test_assignment_rule.py @@ -104,7 +104,7 @@ class TestAutoAssign(FrappeTestCase): frappe.db.delete("ToDo", {"name": d.name}) # add 5 more assignments - for i in range(5): + for _ in range(5): _make_test_record(public=1) # check if each user still has 10 assignments diff --git a/frappe/build.py b/frappe/build.py index 933799b2ce..40d9c98ed5 100644 --- a/frappe/build.py +++ b/frappe/build.py @@ -177,9 +177,6 @@ def symlink(target, link_name, overwrite=False): if not overwrite: return os.symlink(target, link_name) - # os.replace() may fail if files are on different filesystems - link_dir = os.path.dirname(link_name) - # Create link to target with temporary filename while True: temp_link_name = f"tmp{frappe.generate_hash()}" diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 28932ba5e5..832364ab92 100644 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -1036,7 +1036,7 @@ def _drop_site( f"Error: The operation has stopped because backup of {site}'s database failed.", f"Reason: {str(err)}\n", "Fix the issue and try again.", - "Hint: Use 'bench drop-site {0} --force' to force the removal of {0}".format(site), + f"Hint: Use 'bench drop-site {site} --force' to force the removal of {site}", ] click.echo("\n".join(messages)) sys.exit(1) diff --git a/frappe/commands/translate.py b/frappe/commands/translate.py index 5ebae3bfb8..361a19aee2 100644 --- a/frappe/commands/translate.py +++ b/frappe/commands/translate.py @@ -38,9 +38,7 @@ def new_language(context, lang_code, app): frappe.connect() frappe.translate.write_translations_file(app, lang_code) - print( - "File created at ./apps/{app}/{app}/translations/{lang_code}.csv".format(app=app, lang_code=lang_code) - ) + print(f"File created at ./apps/{app}/{app}/translations/{lang_code}.csv") print("You will need to add the language in frappe/geo/languages.json, if you haven't done it already.") diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 0bf5a0fd23..e4b4118c37 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -556,7 +556,7 @@ def jupyter(context): os.mkdir(jupyter_notebooks_path) bin_path = os.path.abspath("../env/bin") print( - """ + f""" Starting Jupyter notebook Run the following in your first cell to connect notebook to frappe ``` @@ -566,7 +566,7 @@ frappe.connect() frappe.local.lang = frappe.db.get_default('lang') frappe.db.connect() ``` - """.format(site=site, sites_path=sites_path) + """ ) os.execv( f"{bin_path}/jupyter", diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index bd57b44a1b..efb53dd590 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -125,11 +125,10 @@ def get_preferred_address(doctype, name, preferred_key="is_primary_address"): FROM `tabAddress` addr, `tabDynamic Link` dl WHERE - dl.parent = addr.name and dl.link_doctype = %s and - dl.link_name = %s and ifnull(addr.disabled, 0) = 0 and - %s = %s - """ - % ("%s", "%s", preferred_key, "%s"), + dl.parent = addr.name and dl.link_doctype = {} and + dl.link_name = {} and ifnull(addr.disabled, 0) = 0 and + {} = {} + """.format("%s", "%s", preferred_key, "%s"), (doctype, name, 1), as_dict=1, ) diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 8d549d9c5a..242b08561e 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -256,7 +256,7 @@ def contact_query(doctype, txt, searchfield, start, page_len, filters): link_name = filters.pop("link_name") return frappe.db.sql( - """select + f"""select `tabContact`.name, `tabContact`.full_name, `tabContact`.company_name from `tabContact`, `tabDynamic Link` @@ -265,12 +265,12 @@ def contact_query(doctype, txt, searchfield, start, page_len, filters): `tabDynamic Link`.parenttype = 'Contact' and `tabDynamic Link`.link_doctype = %(link_doctype)s and `tabDynamic Link`.link_name = %(link_name)s and - `tabContact`.`{key}` like %(txt)s - {mcond} + `tabContact`.`{searchfield}` like %(txt)s + {get_match_cond(doctype)} order by if(locate(%(_txt)s, `tabContact`.full_name), locate(%(_txt)s, `tabContact`.company_name), 99999), `tabContact`.idx desc, `tabContact`.full_name - limit %(start)s, %(page_len)s """.format(mcond=get_match_cond(doctype), key=searchfield), + limit %(start)s, %(page_len)s """, { "txt": "%" + txt + "%", "_txt": txt.replace("%", ""), diff --git a/frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.py b/frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.py index 9bb661d90c..12d31b158f 100644 --- a/frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.py +++ b/frappe/contacts/report/addresses_and_contacts/addresses_and_contacts.py @@ -52,7 +52,6 @@ def get_columns(filters): def get_data(filters): - data = [] reference_doctype = filters.get("reference_doctype") reference_name = filters.get("reference_name") diff --git a/frappe/core/doctype/activity_log/activity_log.py b/frappe/core/doctype/activity_log/activity_log.py index b24f7368b4..68372ea7af 100644 --- a/frappe/core/doctype/activity_log/activity_log.py +++ b/frappe/core/doctype/activity_log/activity_log.py @@ -53,7 +53,7 @@ class ActivityLog(Document): def set_ip_address(self): if self.operation in ("Login", "Logout"): - self.ip_address = getattr(frappe.local, "request_ip") + self.ip_address = frappe.local.request_ip @staticmethod def clear_old_logs(days=None): diff --git a/frappe/core/doctype/data_import/data_import.py b/frappe/core/doctype/data_import/data_import.py index 8504aa1b04..ab9dfa9372 100644 --- a/frappe/core/doctype/data_import/data_import.py +++ b/frappe/core/doctype/data_import/data_import.py @@ -271,7 +271,7 @@ def export_json(doctype, path, filters=None, or_filters=None, name=None, order_b for key in del_keys: if key in doc: del doc[key] - for k, v in doc.items(): + for v in doc.values(): if isinstance(v, list): for child in v: for key in del_keys + ("docstatus", "doctype", "modified", "name"): diff --git a/frappe/core/doctype/data_import/importer.py b/frappe/core/doctype/data_import/importer.py index a4d25074a1..fe4b1bc169 100644 --- a/frappe/core/doctype/data_import/importer.py +++ b/frappe/core/doctype/data_import/importer.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE -import io import json import os import re @@ -525,7 +524,6 @@ class ImportFile: # subsequent rows that have blank values in parent columns # are considered as child rows parent_column_indexes = self.header.get_column_indexes(self.doctype) - parent_row_values = first_row.get_values(parent_column_indexes) data_without_first_row = data[1:] for row in data_without_first_row: @@ -656,7 +654,7 @@ class Row: for key in frappe.model.default_fields + frappe.model.child_table_fields + ("__islocal",): doc.pop(key, None) - for col, value in zip(columns, values): + for col, value in zip(columns, values, strict=False): df = col.df if value in INVALID_VALUES: value = None @@ -751,7 +749,7 @@ class Row: def parse_value(self, value, col): df = col.df - if isinstance(value, (datetime, date)) and df.fieldtype in ["Date", "Datetime"]: + if isinstance(value, datetime | date) and df.fieldtype in ["Date", "Datetime"]: return value value = cstr(value) @@ -774,7 +772,7 @@ class Row: return value def get_date(self, value, column): - if isinstance(value, (datetime, date)): + if isinstance(value, datetime | date): return value date_format = column.date_format @@ -938,7 +936,7 @@ class Column: """ def guess_date_format(d): - if isinstance(d, (datetime, date, time)): + if isinstance(d, datetime | date | time): if self.df.fieldtype == "Date": return "%Y-%m-%d" if self.df.fieldtype == "Datetime": @@ -1137,7 +1135,6 @@ def build_fields_dict_for_column_matching(parent_doctype): label = (df.label or "").strip() translated_label = _(label) - parent = df.parent or parent_doctype if parent_doctype == doctype: # for parent doctypes keys will be diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index fdd6f51e9c..40b3b31b61 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -1363,11 +1363,9 @@ def validate_fields(meta): if not d.get("__islocal") and frappe.db.has_column(d.parent, d.fieldname): has_non_unique_values = frappe.db.sql( - """select `{fieldname}`, count(*) - from `tab{doctype}` where ifnull(`{fieldname}`, '') != '' - group by `{fieldname}` having count(*) > 1 limit 1""".format( - doctype=d.parent, fieldname=d.fieldname - ) + f"""select `{d.fieldname}`, count(*) + from `tab{d.parent}` where ifnull(`{d.fieldname}`, '') != '' + group by `{d.fieldname}` having count(*) > 1 limit 1""" ) if has_non_unique_values and has_non_unique_values[0][0]: @@ -1541,7 +1539,7 @@ def validate_fields(meta): field.options = "\n".join(options_list) def scrub_fetch_from(field): - if hasattr(field, "fetch_from") and getattr(field, "fetch_from"): + if hasattr(field, "fetch_from") and field.fetch_from: field.fetch_from = field.fetch_from.strip("\n").strip() def validate_data_field_type(docfield): @@ -1826,7 +1824,7 @@ def make_module_and_roles(doc, perm_fieldname="permissions"): r.desk_access = 1 r.flags.ignore_mandatory = r.flags.ignore_permissions = True r.insert() - except frappe.DoesNotExistError as e: + except frappe.DoesNotExistError: pass except frappe.db.ProgrammingError as e: if frappe.db.is_table_missing(e): diff --git a/frappe/core/doctype/error_log/test_error_log.py b/frappe/core/doctype/error_log/test_error_log.py index 22eeea329e..98c87dda52 100644 --- a/frappe/core/doctype/error_log/test_error_log.py +++ b/frappe/core/doctype/error_log/test_error_log.py @@ -52,15 +52,21 @@ _THROW_EXC = """ frappe.exceptions.ValidationError: what """ -TEST_EXCEPTIONS = { - "erpnext (app)": _RAW_EXC, - "erpnext (app)": _THROW_EXC, -} +TEST_EXCEPTIONS = ( + ( + "erpnext (app)", + _RAW_EXC, + ), + ( + "erpnext (app)", + _THROW_EXC, + ), +) class TestExceptionSourceGuessing(FrappeTestCase): @patch.object(frappe, "get_installed_apps", return_value=["frappe", "erpnext", "3pa"]) def test_exc_source_guessing(self, _installed_apps): - for source, exc in TEST_EXCEPTIONS.items(): + for source, exc in TEST_EXCEPTIONS: result = guess_exception_source(exc) self.assertEqual(result, source) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 9d4b8f6a4a..d203894cce 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -137,7 +137,7 @@ class File(Document): if not self.attached_to_doctype: return - if not self.attached_to_name or not isinstance(self.attached_to_name, (str, int)): + if not self.attached_to_name or not isinstance(self.attached_to_name, str | int): frappe.throw(_("Attached To Name must be a string or an integer"), frappe.ValidationError) if self.attached_to_field and SPECIAL_CHAR_PATTERN.search(self.attached_to_field): diff --git a/frappe/core/doctype/page/page.py b/frappe/core/doctype/page/page.py index 872b6c0012..48d783f14e 100644 --- a/frappe/core/doctype/page/page.py +++ b/frappe/core/doctype/page/page.py @@ -88,14 +88,13 @@ class Page(Document): if not os.path.exists(path + ".js"): with open(path + ".js", "w") as f: f.write( - """frappe.pages['%s'].on_page_load = function(wrapper) { - var page = frappe.ui.make_app_page({ + f"""frappe.pages['{self.name}'].on_page_load = function(wrapper) {{ + var page = frappe.ui.make_app_page({{ parent: wrapper, - title: '%s', + title: '{self.title}', single_column: true - }); -}""" - % (self.name, self.title) + }}); +}}""" ) def as_dict(self, no_nulls=False): diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py index e14ec41fde..c108c8ee6e 100644 --- a/frappe/core/doctype/report/report.py +++ b/frappe/core/doctype/report/report.py @@ -301,7 +301,7 @@ class Report(Document): if filters: for key, value in filters.items(): condition, _value = "=", value - if isinstance(value, (list, tuple)): + if isinstance(value, list | tuple): condition, _value = value _filters.append([key, condition, _value]) @@ -360,7 +360,7 @@ class Report(Document): def build_data_dict(self, result, columns): data = [] for row in result: - if isinstance(row, (list, tuple)): + if isinstance(row, list | tuple): _row = frappe._dict() for i, val in enumerate(row): _row[columns[i].get("fieldname")] = val diff --git a/frappe/core/doctype/report/test_report.py b/frappe/core/doctype/report/test_report.py index cda004c00c..b22f4b491c 100644 --- a/frappe/core/doctype/report/test_report.py +++ b/frappe/core/doctype/report/test_report.py @@ -131,7 +131,12 @@ class TestReport(FrappeTestCase): self.assertListEqual(["email"], [column.get("fieldname") for column in columns]) admin_dict = frappe.core.utils.find(result, lambda d: d["name"] == "Administrator") self.assertDictEqual( - {"name": "Administrator", "user_type": "System User", "email": "admin@example.com"}, admin_dict + { + "name": "Administrator", + "user_type": "System User", + "email": "admin@example.com", + }, + admin_dict, ) def test_report_with_custom_column(self): @@ -156,10 +161,18 @@ class TestReport(FrappeTestCase): ) result = response.get("result") columns = response.get("columns") - self.assertListEqual(["name", "email", "user_type"], [column.get("fieldname") for column in columns]) + self.assertListEqual( + ["name", "email", "user_type"], + [column.get("fieldname") for column in columns], + ) admin_dict = frappe.core.utils.find(result, lambda d: d["name"] == "Administrator") self.assertDictEqual( - {"name": "Administrator", "user_type": "System User", "email": "admin@example.com"}, admin_dict + { + "name": "Administrator", + "user_type": "System User", + "email": "admin@example.com", + }, + admin_dict, ) def test_report_permissions(self): @@ -167,9 +180,7 @@ class TestReport(FrappeTestCase): frappe.db.delete("Has Role", {"parent": frappe.session.user, "role": "Test Has Role"}) frappe.db.commit() if not frappe.db.exists("Role", "Test Has Role"): - role = frappe.get_doc({"doctype": "Role", "role_name": "Test Has Role"}).insert( - ignore_permissions=True - ) + frappe.get_doc({"doctype": "Role", "role_name": "Test Has Role"}).insert(ignore_permissions=True) if not frappe.db.exists("Report", "Test Report"): report = frappe.get_doc( @@ -253,18 +264,18 @@ class TestReport(FrappeTestCase): report.report_script = """ totals = {} for user in frappe.get_all('User', fields = ['name', 'user_type', 'creation']): - if not user.user_type in totals: - totals[user.user_type] = 0 - totals[user.user_type] = totals[user.user_type] + 1 + if not user.user_type in totals: + totals[user.user_type] = 0 + totals[user.user_type] = totals[user.user_type] + 1 data = [ - [ - {'fieldname': 'type', 'label': 'Type'}, - {'fieldname': 'value', 'label': 'Value'} - ], - [ - {"type":key, "value": value} for key, value in totals.items() - ] + [ + {'fieldname': 'type', 'label': 'Type'}, + {'fieldname': 'value', 'label': 'Value'} + ], + [ + {"type":key, "value": value} for key, value in totals.items() + ] ] """ report.save() @@ -299,13 +310,13 @@ data = [ report.report_script = """ totals = {} for user in frappe.get_all('User', fields = ['name', 'user_type', 'creation']): - if not user.user_type in totals: - totals[user.user_type] = 0 - totals[user.user_type] = totals[user.user_type] + 1 + if not user.user_type in totals: + totals[user.user_type] = 0 + totals[user.user_type] = totals[user.user_type] + 1 result = [ - {"type":key, "value": value} for key, value in totals.items() - ] + {"type":key, "value": value} for key, value in totals.items() + ] """ report.save() @@ -344,15 +355,40 @@ result = [ report_settings = {"tree": True, "parent_field": "parent_value"} columns = [ - {"fieldname": "parent_column", "label": "Parent Column", "fieldtype": "Data", "width": 10}, - {"fieldname": "column_1", "label": "Column 1", "fieldtype": "Float", "width": 10}, - {"fieldname": "column_2", "label": "Column 2", "fieldtype": "Float", "width": 10}, + { + "fieldname": "parent_column", + "label": "Parent Column", + "fieldtype": "Data", + "width": 10, + }, + { + "fieldname": "column_1", + "label": "Column 1", + "fieldtype": "Float", + "width": 10, + }, + { + "fieldname": "column_2", + "label": "Column 2", + "fieldtype": "Float", + "width": 10, + }, ] result = [ {"parent_column": "Parent 1", "column_1": 200, "column_2": 150.50}, - {"parent_column": "Child 1", "column_1": 100, "column_2": 75.25, "parent_value": "Parent 1"}, - {"parent_column": "Child 2", "column_1": 100, "column_2": 75.25, "parent_value": "Parent 1"}, + { + "parent_column": "Child 1", + "column_1": 100, + "column_2": 75.25, + "parent_value": "Parent 1", + }, + { + "parent_column": "Child 2", + "column_1": 100, + "column_2": 75.25, + "parent_value": "Parent 1", + }, ] result = add_total_row( @@ -369,13 +405,13 @@ result = [ def test_cte_in_query_report(self): cte_query = textwrap.dedent( """ - with enabled_users as ( - select name - from `tabUser` - where enabled = 1 - ) - select * from enabled_users; - """ + with enabled_users as ( + select name + from `tabUser` + where enabled = 1 + ) + select * from enabled_users; + """ ) report = frappe.get_doc( diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py index a995f9d57b..d5b405b96d 100644 --- a/frappe/core/doctype/server_script/server_script.py +++ b/frappe/core/doctype/server_script/server_script.py @@ -210,7 +210,7 @@ class ServerScript(Document): if key.startswith("_"): continue value = obj[key] - if isinstance(value, (NamespaceDict, dict)) and value: + if isinstance(value, NamespaceDict | dict) and value: if key == "form_dict": out.append(["form_dict", 7]) continue @@ -222,7 +222,7 @@ class ServerScript(Document): score = 0 elif isinstance(value, ModuleType): score = 10 - elif isinstance(value, (FunctionType, MethodType)): + elif isinstance(value, FunctionType | MethodType): score = 9 elif isinstance(value, type): score = 8 diff --git a/frappe/core/doctype/server_script/test_server_script.py b/frappe/core/doctype/server_script/test_server_script.py index cbf3ef977a..e7735c8fc9 100644 --- a/frappe/core/doctype/server_script/test_server_script.py +++ b/frappe/core/doctype/server_script/test_server_script.py @@ -218,7 +218,7 @@ frappe.qb.from_(todo).select(todo.name).where(todo.name == "{todo.name}").run() name="test_nested_scripts_1", script_type="API", api_method="test_nested_scripts_1", - script=f"""log("nothing")""", + script="""log("nothing")""", ) script.insert() script.execute_method() @@ -228,7 +228,7 @@ frappe.qb.from_(todo).select(todo.name).where(todo.name == "{todo.name}").run() name="test_nested_scripts_2", script_type="API", api_method="test_nested_scripts_2", - script=f"""frappe.call("test_nested_scripts_1")""", + script="""frappe.call("test_nested_scripts_1")""", ) script.insert() script.execute_method() diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 9afa29df26..2290372ec8 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -574,10 +574,9 @@ class User(Document): has_fields = [d.get("name") for d in desc if d.get("name") in ["owner", "modified_by"]] for field in has_fields: frappe.db.sql( - """UPDATE `%s` - SET `%s` = %s - WHERE `%s` = %s""" - % (tab, field, "%s", field, "%s"), + """UPDATE `{}` + SET `{}` = {} + WHERE `{}` = {}""".format(tab, field, "%s", field, "%s"), (new_name, old_name), ) @@ -620,7 +619,7 @@ class User(Document): def ensure_unique_roles(self): exists = [] - for i, d in enumerate(self.get("roles")): + for d in self.get("roles"): if (not d.role) or (d.role in exists): self.get("roles").remove(d) else: diff --git a/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.py b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.py index b865c23b11..bf1694b164 100644 --- a/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.py +++ b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.py @@ -36,11 +36,7 @@ def get_columns_and_fields(doctype): if df.in_list_view and df.fieldtype in data_fieldtypes: fields.append(f"`{df.fieldname}`") fieldtype = f"Link/{df.options}" if df.fieldtype == "Link" else df.fieldtype - columns.append( - "{label}:{fieldtype}:{width}".format( - label=df.label, fieldtype=fieldtype, width=df.width or 100 - ) - ) + columns.append(f"{df.label}:{fieldtype}:{df.width or 100}") return columns, fields diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index f0f415474c..7d374785dc 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -592,11 +592,11 @@ class CustomizeForm(Document): max_length = cint(frappe.db.type_map.get(df.fieldtype)[1]) fieldname = df.fieldname docs = frappe.db.sql( - """ + f""" SELECT name, {fieldname}, LENGTH({fieldname}) AS len - FROM `tab{doctype}` + FROM `tab{self.doc_type}` WHERE LENGTH({fieldname}) > {max_length} - """.format(fieldname=fieldname, doctype=self.doc_type, max_length=max_length), + """, as_dict=True, ) label = df.label diff --git a/frappe/custom/report/audit_system_hooks/audit_system_hooks.py b/frappe/custom/report/audit_system_hooks/audit_system_hooks.py index 0c3b495271..07b8e18b4d 100644 --- a/frappe/custom/report/audit_system_hooks/audit_system_hooks.py +++ b/frappe/custom/report/audit_system_hooks/audit_system_hooks.py @@ -35,7 +35,7 @@ def get_data(): v = delist(v) - if isinstance(v, (dict, list)): + if isinstance(v, dict | list): try: return frappe.as_json(v) except Exception: diff --git a/frappe/database/database.py b/frappe/database/database.py index 83b426236f..df7a968eb3 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -103,8 +103,8 @@ class Database: def connect(self): """Connects to a database as set in `site_config.json`.""" - self._conn: Union["MariadbConnection", "PostgresConnection"] = self.get_connection() - self._cursor: Union["MariadbCursor", "PostgresCursor"] = self._conn.cursor() + self._conn: "MariadbConnection" | "PostgresConnection" = self.get_connection() + self._cursor: "MariadbCursor" | "PostgresCursor" = self._conn.cursor() try: if execution_timeout := get_query_execution_timeout(): @@ -183,7 +183,7 @@ class Database: {"name": "a%", "owner":"test@example.com"}) """ - if isinstance(query, (MySQLQueryBuilder, PostgreSQLQueryBuilder)): + if isinstance(query, MySQLQueryBuilder | PostgreSQLQueryBuilder): frappe.errprint("Use run method to execute SQL queries generated by Query Engine") debug = debug or getattr(self, "debug", False) @@ -212,7 +212,7 @@ class Database: if values == EmptyQueryValues: values = None - elif not isinstance(values, (tuple, dict, list)): + elif not isinstance(values, tuple | dict | list): values = (values,) query, values = self._transform_query(query, values) @@ -302,7 +302,7 @@ class Database: elif as_dict: keys = [column[0] for column in self._cursor.description] for row in result: - row = frappe._dict(zip(keys, row)) + row = frappe._dict(zip(keys, row, strict=False)) if update: row.update(update) yield row @@ -371,7 +371,7 @@ class Database: return query % { k: frappe.db.escape(v) if isinstance(v, str) else v for k, v in values.items() } - elif isinstance(values, (list, tuple)): + elif isinstance(values, list | tuple): return query % tuple(frappe.db.escape(v) if isinstance(v, str) else v for v in values) return query, values @@ -438,7 +438,7 @@ class Database: if result: keys = [column[0] for column in self._cursor.description] - return [frappe._dict(zip(keys, row)) for row in result] + return [frappe._dict(zip(keys, row, strict=False)) for row in result] @staticmethod def clear_db_table_cache(query): diff --git a/frappe/database/mariadb/database.py b/frappe/database/mariadb/database.py index 1c07d77d26..908e7bb479 100644 --- a/frappe/database/mariadb/database.py +++ b/frappe/database/mariadb/database.py @@ -291,18 +291,18 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): def create_global_search_table(self): if "__global_search" not in self.get_tables(): self.sql( - """create table __global_search( + f"""create table __global_search( doctype varchar(100), - name varchar({0}), - title varchar({0}), + name varchar({self.VARCHAR_LEN}), + title varchar({self.VARCHAR_LEN}), content text, fulltext(content), - route varchar({0}), + route varchar({self.VARCHAR_LEN}), published int(1) not null default 0, unique `doctype_name` (doctype, name)) COLLATE=utf8mb4_unicode_ci ENGINE=MyISAM - CHARACTER SET=utf8mb4""".format(self.VARCHAR_LEN) + CHARACTER SET=utf8mb4""" ) def create_user_settings_table(self): @@ -322,7 +322,7 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): def get_table_columns_description(self, table_name): """Return list of columns with descriptions.""" return self.sql( - """select + f"""select column_name as 'name', column_type as 'type', column_default as 'default', @@ -338,7 +338,7 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): column_key = 'UNI' as 'unique', (is_nullable = 'NO') AS 'not_nullable' from information_schema.columns as columns - where table_name = '{table_name}' """.format(table_name=table_name), + where table_name = '{table_name}' """, as_dict=1, ) @@ -359,8 +359,8 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): def has_index(self, table_name, index_name): return self.sql( - """SHOW INDEX FROM `{table_name}` - WHERE Key_name='{index_name}'""".format(table_name=table_name, index_name=index_name) + f"""SHOW INDEX FROM `{table_name}` + WHERE Key_name='{index_name}'""" ) def get_column_index(self, table_name: str, fieldname: str, unique: bool = False) -> frappe._dict | None: @@ -401,9 +401,8 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): if not self.has_index(table_name, index_name): self.commit() self.sql( - """ALTER TABLE `%s` - ADD INDEX `%s`(%s)""" - % (table_name, index_name, ", ".join(fields)) + """ALTER TABLE `{}` + ADD INDEX `{}`({})""".format(table_name, index_name, ", ".join(fields)) ) def add_unique(self, doctype, fields, constraint_name=None): @@ -419,9 +418,8 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): ): self.commit() self.sql( - """alter table `tab%s` - add unique `%s`(%s)""" - % (doctype, constraint_name, ", ".join(fields)) + """alter table `tab{}` + add unique `{}`({})""".format(doctype, constraint_name, ", ".join(fields)) ) def updatedb(self, doctype, meta=None): diff --git a/frappe/database/mariadb/setup_db.py b/frappe/database/mariadb/setup_db.py index 5ce6e47a42..96e80e741c 100644 --- a/frappe/database/mariadb/setup_db.py +++ b/frappe/database/mariadb/setup_db.py @@ -113,10 +113,7 @@ def check_database_settings(): result = True for key, expected_value in REQUIRED_MARIADB_CONFIG.items(): if mariadb_variables.get(key) != expected_value: - print( - "For key %s. Expected value %s, found value %s" - % (key, expected_value, mariadb_variables.get(key)) - ) + print(f"For key {key}. Expected value {expected_value}, found value {mariadb_variables.get(key)}") result = False if not result: diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index a0030432dc..003455b5dd 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -288,14 +288,14 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def create_global_search_table(self): if "__global_search" not in self.get_tables(): self.sql( - """create table "__global_search"( + f"""create table "__global_search"( doctype varchar(100), - name varchar({0}), - title varchar({0}), + name varchar({self.VARCHAR_LEN}), + title varchar({self.VARCHAR_LEN}), content text, - route varchar({0}), + route varchar({self.VARCHAR_LEN}), published int not null default 0, - unique (doctype, name))""".format(self.VARCHAR_LEN) + unique (doctype, name))""" ) def create_user_settings_table(self): @@ -338,8 +338,8 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def has_index(self, table_name, index_name): return self.sql( - """SELECT 1 FROM pg_indexes WHERE tablename='{table_name}' - and indexname='{index_name}' limit 1""".format(table_name=table_name, index_name=index_name) + f"""SELECT 1 FROM pg_indexes WHERE tablename='{table_name}' + and indexname='{index_name}' limit 1""" ) def add_index(self, doctype: str, fields: list, index_name: str = None): @@ -368,16 +368,15 @@ class PostgresDatabase(PostgresExceptionUtil, Database): ): self.commit() self.sql( - """ALTER TABLE `tab%s` - ADD CONSTRAINT %s UNIQUE (%s)""" - % (doctype, constraint_name, ", ".join(fields)) + """ALTER TABLE `tab{}` + ADD CONSTRAINT {} UNIQUE ({})""".format(doctype, constraint_name, ", ".join(fields)) ) def get_table_columns_description(self, table_name): """Return list of columns with description.""" # pylint: disable=W1401 return self.sql( - """ + f""" SELECT a.column_name AS name, CASE LOWER(a.data_type) WHEN 'character varying' THEN CONCAT('varchar(', a.character_maximum_length ,')') @@ -398,7 +397,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): ON SUBSTRING(b.indexdef, '(.*)') LIKE CONCAT('%', a.column_name, '%') WHERE a.table_name = '{table_name}' GROUP BY a.column_name, a.data_type, a.column_default, a.character_maximum_length, a.is_nullable; - """.format(table_name=table_name), + """, as_dict=1, ) @@ -441,7 +440,7 @@ def modify_query(query): def modify_values(values): def modify_value(value): - if isinstance(value, (list, tuple)): + if isinstance(value, list | tuple): value = tuple(modify_values(value)) elif isinstance(value, int): @@ -455,7 +454,7 @@ def modify_values(values): if isinstance(values, dict): for k, v in values.items(): values[k] = modify_value(v) - elif isinstance(values, (tuple, list)): + elif isinstance(values, tuple | list): new_values = [] for val in values: new_values.append(modify_value(val)) diff --git a/frappe/database/postgres/schema.py b/frappe/database/postgres/schema.py index 18870e299d..018de93f41 100644 --- a/frappe/database/postgres/schema.py +++ b/frappe/database/postgres/schema.py @@ -54,16 +54,14 @@ class PostgresTable(DBTable): def create_indexes(self): create_index_query = "" - for key, col in self.columns.items(): + for col in self.columns.values(): if ( col.set_index and col.fieldtype in frappe.db.type_map and frappe.db.type_map.get(col.fieldtype)[0] not in ("text", "longtext") ): create_index_query += ( - 'CREATE INDEX IF NOT EXISTS "{index_name}" ON `{table_name}`(`{field}`);'.format( - index_name=col.fieldname, table_name=self.table_name, field=col.fieldname - ) + f'CREATE INDEX IF NOT EXISTS "{col.fieldname}" ON `{self.table_name}`(`{col.fieldname}`);' ) if create_index_query: # nosemgrep @@ -115,9 +113,7 @@ class PostgresTable(DBTable): for col in self.add_index: # if index key not exists create_contraint_query += ( - 'CREATE INDEX IF NOT EXISTS "{index_name}" ON `{table_name}`(`{field}`);'.format( - index_name=col.fieldname, table_name=self.table_name, field=col.fieldname - ) + f'CREATE INDEX IF NOT EXISTS "{col.fieldname}" ON `{self.table_name}`(`{col.fieldname}`);' ) for col in self.add_unique: diff --git a/frappe/database/query.py b/frappe/database/query.py index bded4e3aee..a94f07ac06 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -99,7 +99,7 @@ class Engine: # add fields self.fields = self.parse_fields(fields) if not self.fields: - self.fields = [getattr(self.table, "name")] + self.fields = [self.table.name] self.query._child_queries = [] for field in self.fields: @@ -117,7 +117,7 @@ class Engine: if filters is None: return - if isinstance(filters, (str, int)): + if isinstance(filters, str | int): filters = {"name": str(filters)} if isinstance(filters, Criterion): @@ -126,14 +126,14 @@ class Engine: elif isinstance(filters, dict): self.apply_dict_filters(filters) - elif isinstance(filters, (list, tuple)): - if all(isinstance(d, (str, int)) for d in filters) and len(filters) > 0: + elif isinstance(filters, list | tuple): + if all(isinstance(d, str | int) for d in filters) and len(filters) > 0: self.apply_dict_filters({"name": ("in", filters)}) else: for filter in filters: - if isinstance(filter, (str, int, Criterion, dict)): + if isinstance(filter, str | int | Criterion | dict): self.apply_filters(filter) - elif isinstance(filter, (list, tuple)): + elif isinstance(filter, list | tuple): self.apply_list_filters(filter) def apply_list_filters(self, filter: list): @@ -150,7 +150,7 @@ class Engine: def apply_dict_filters(self, filters: dict[str, str | int | list]): for field, value in filters.items(): operator = "=" - if isinstance(value, (list, tuple)): + if isinstance(value, list | tuple): operator, value = value self._apply_filter(field, value, operator) @@ -187,7 +187,7 @@ class Engine: if isinstance(_value, bool): _value = int(_value) - elif not _value and isinstance(_value, (list, tuple)): + elif not _value and isinstance(_value, list | tuple): _value = ("",) # Nested set @@ -279,7 +279,7 @@ class Engine: return MARIADB_SPECIFIC_COMMENT.sub("", stripped_field) return stripped_field - if isinstance(fields, (list, tuple)): + if isinstance(fields, list | tuple): return [_sanitize_field(field) for field in fields] elif isinstance(fields, str): return _sanitize_field(fields) @@ -304,10 +304,10 @@ class Engine: if not fields: return [] fields = self.sanitize_fields(fields) - if isinstance(fields, (list, tuple, set)) and None in fields and Field not in fields: + if isinstance(fields, list | tuple | set) and None in fields and Field not in fields: return [] - if not isinstance(fields, (list, tuple)): + if not isinstance(fields, list | tuple): fields = [fields] def parse_field(field: str): diff --git a/frappe/database/schema.py b/frappe/database/schema.py index 6994fa88c8..c336ab5ba2 100644 --- a/frappe/database/schema.py +++ b/frappe/database/schema.py @@ -144,9 +144,7 @@ class DBTable: try: # check for truncation max_length = frappe.db.sql( - """SELECT MAX(CHAR_LENGTH(`{fieldname}`)) FROM `tab{doctype}`""".format( - fieldname=col.fieldname, doctype=self.doctype - ) + f"""SELECT MAX(CHAR_LENGTH(`{col.fieldname}`)) FROM `tab{self.doctype}`""" ) except frappe.db.InternalError as e: diff --git a/frappe/defaults.py b/frappe/defaults.py index d8ba0dc93b..af95c273a1 100644 --- a/frappe/defaults.py +++ b/frappe/defaults.py @@ -21,7 +21,7 @@ def get_user_default(key, user=None): d = user_defaults.get(key, None) if is_a_user_permission_key(key): - if d and isinstance(d, (list, tuple)) and len(d) == 1: + if d and isinstance(d, list | tuple) and len(d) == 1: # Use User Permission value when only when it has a single value d = d[0] else: @@ -31,7 +31,7 @@ def get_user_default(key, user=None): # If no default value is found, use the User Permission value d = user_permission_default - value = isinstance(d, (list, tuple)) and d[0] or d + value = isinstance(d, list | tuple) and d[0] or d if not_in_user_permission(key, value, user): return @@ -61,14 +61,14 @@ def get_user_default_as_list(key, user=None): d = user_defaults.get(key, None) if is_a_user_permission_key(key): - if d and isinstance(d, (list, tuple)) and len(d) == 1: + if d and isinstance(d, list | tuple) and len(d) == 1: # Use User Permission value when only when it has a single value d = [d[0]] else: d = user_defaults.get(frappe.scrub(key), None) - d = list(filter(None, (not isinstance(d, (list, tuple))) and [d] or d)) + d = list(filter(None, (not isinstance(d, list | tuple)) and [d] or d)) # filter default values if not found in user permission return [value for value in d if not not_in_user_permission(key, value)] @@ -135,7 +135,7 @@ def add_global_default(key, value): def get_global_default(key): d = get_defaults().get(key, None) - value = isinstance(d, (list, tuple)) and d[0] or d + value = isinstance(d, list | tuple) and d[0] or d if not_in_user_permission(key, value): return diff --git a/frappe/deferred_insert.py b/frappe/deferred_insert.py index 5c7e7a7f0d..fd370d8ac5 100644 --- a/frappe/deferred_insert.py +++ b/frappe/deferred_insert.py @@ -13,7 +13,7 @@ queue_prefix = "insert_queue_for_" def deferred_insert(doctype: str, records: list[Union[dict, "Document"]] | str): - if isinstance(records, (dict, list)): + if isinstance(records, dict | list): _records = json.dumps(records) else: _records = records diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index c31be72461..26968f8430 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -559,11 +559,11 @@ def save_new_widget(doc, page, blocks, new_widgets): json_config = widgets and dumps(widgets, sort_keys=True, indent=4) # Error log body - log = """ - page: {} - config: {} - exception: {} - """.format(page, json_config, e) + log = f""" + page: {page} + config: {json_config} + exception: {e} + """ doc.log_error("Could not save customization", log) raise diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index 0c0a96adba..59efa6e873 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -124,9 +124,7 @@ def get_non_standard_warning_message(non_standard_docs_map): def get_html(docs, doctype): html = f"

{frappe.bold(doctype)}

" for doc in docs: - html += ''.format( - doctype=doctype, doc=doc - ) + html += f'' html += "
" return html diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index a4345f269f..318f139a33 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -55,7 +55,7 @@ def get_permission_query_conditions(user): module_condition = """`tabDashboard Chart`.`module` in ({allowed_modules}) or `tabDashboard Chart`.`module` is NULL""".format(allowed_modules=",".join(allowed_modules)) - return """ + return f""" ((`tabDashboard Chart`.`chart_type` in ('Count', 'Sum', 'Average') and {doctype_condition}) or @@ -63,11 +63,7 @@ def get_permission_query_conditions(user): and {report_condition})) and ({module_condition}) - """.format( - doctype_condition=doctype_condition, - report_condition=report_condition, - module_condition=module_condition, - ) + """ def has_permission(doc, ptype, user): @@ -248,9 +244,7 @@ def get_heatmap_chart_config(chart, filters, heatmap_year): doctype, fields=[ timestamp_field, - "{aggregate_function}({value_field})".format( - aggregate_function=aggregate_function, value_field=value_field - ), + f"{aggregate_function}({value_field})", ], filters=filters, group_by=f"date({datefield})", @@ -307,7 +301,7 @@ def get_result(data, timegrain, from_date, to_date, chart_type): result = [[date, 0] for date in dates] data_index = 0 if data: - for i, d in enumerate(result): + for d in result: count = 0 while data_index < len(data) and getdate(data[data_index][0]) <= d[0]: d[1] += data[data_index][1] diff --git a/frappe/desk/doctype/event/event.py b/frappe/desk/doctype/event/event.py index c35e4ef136..0765ad9f50 100644 --- a/frappe/desk/doctype/event/event.py +++ b/frappe/desk/doctype/event/event.py @@ -221,9 +221,7 @@ def delete_communication(event, reference_doctype, reference_docname): def get_permission_query_conditions(user): if not user: user = frappe.session.user - return """(`tabEvent`.`event_type`='Public' or `tabEvent`.`owner`={user})""".format( - user=frappe.db.escape(user), - ) + return f"""(`tabEvent`.`event_type`='Public' or `tabEvent`.`owner`={frappe.db.escape(user)})""" def has_permission(doc, user): diff --git a/frappe/desk/doctype/kanban_board/kanban_board.py b/frappe/desk/doctype/kanban_board/kanban_board.py index c3a96c3c42..c8d26acb03 100644 --- a/frappe/desk/doctype/kanban_board/kanban_board.py +++ b/frappe/desk/doctype/kanban_board/kanban_board.py @@ -52,9 +52,7 @@ def get_permission_query_conditions(user): if user == "Administrator": return "" - return """(`tabKanban Board`.private=0 or `tabKanban Board`.owner={user})""".format( - user=frappe.db.escape(user) - ) + return f"""(`tabKanban Board`.private=0 or `tabKanban Board`.owner={frappe.db.escape(user)})""" def has_permission(doc, ptype, user): diff --git a/frappe/desk/doctype/number_card/number_card.py b/frappe/desk/doctype/number_card/number_card.py index 034dff7f68..aea6743ce1 100644 --- a/frappe/desk/doctype/number_card/number_card.py +++ b/frappe/desk/doctype/number_card/number_card.py @@ -101,11 +101,11 @@ def get_permission_query_conditions(user=None): module_condition = """`tabNumber Card`.`module` in ({allowed_modules}) or `tabNumber Card`.`module` is NULL""".format(allowed_modules=",".join(allowed_modules)) - return """ + return f""" {doctype_condition} and {module_condition} - """.format(doctype_condition=doctype_condition, module_condition=module_condition) + """ def has_permission(doc, ptype, user): @@ -141,11 +141,7 @@ def get_result(doc, filters, to_date=None): if function == "count": fields = [f"{function}(*) as result"] else: - fields = [ - "{function}({based_on}) as result".format( - function=function, based_on=doc.aggregate_function_based_on - ) - ] + fields = [f"{function}({doc.aggregate_function_based_on}) as result"] if not filters: filters = [] diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index c51186a493..23300b0a1c 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -214,7 +214,7 @@ def get_references_across_doctypes( for k, v in references_by_dlink_fields.items(): references.setdefault(k, []).extend(v) - for doctype, links in references.items(): + for links in references.values(): for link in links: link["is_child"] = link["doctype"] in all_child_tables return references diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index e090cf921e..d3c448fa03 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -286,9 +286,9 @@ def get_communication_data( conditions = "" if after: # find after a particular date - conditions += """ - AND C.creation > {} - """.format(after) + conditions += f""" + AND C.creation > {after} + """ if doctype == "User": conditions += """ @@ -296,23 +296,23 @@ def get_communication_data( """ # communications linked to reference_doctype - part1 = """ + part1 = f""" SELECT {fields} FROM `tabCommunication` as C WHERE C.communication_type IN ('Communication', 'Feedback', 'Automated Message') AND (C.reference_doctype = %(doctype)s AND C.reference_name = %(name)s) {conditions} - """.format(fields=fields, conditions=conditions) + """ # communications linked in Timeline Links - part2 = """ + part2 = f""" SELECT {fields} FROM `tabCommunication` as C INNER JOIN `tabCommunication Link` ON C.name=`tabCommunication Link`.parent WHERE C.communication_type IN ('Communication', 'Feedback', 'Automated Message') AND `tabCommunication Link`.link_doctype = %(doctype)s AND `tabCommunication Link`.link_name = %(name)s {conditions} - """.format(fields=fields, conditions=conditions) + """ return frappe.db.sql( """ diff --git a/frappe/desk/form/utils.py b/frappe/desk/form/utils.py index 353dea305f..b93ebdb5bc 100644 --- a/frappe/desk/form/utils.py +++ b/frappe/desk/form/utils.py @@ -105,6 +105,4 @@ def get_next(doctype, value, prev, filters=None, sort_order="desc", sort_field=" def get_pdf_link(doctype, docname, print_format="Standard", no_letterhead=0): - return "/api/method/frappe.utils.print_format.download_pdf?doctype={doctype}&name={docname}&format={print_format}&no_letterhead={no_letterhead}".format( - doctype=doctype, docname=docname, print_format=print_format, no_letterhead=no_letterhead - ) + return f"/api/method/frappe.utils.print_format.download_pdf?doctype={doctype}&name={docname}&format={print_format}&no_letterhead={no_letterhead}" diff --git a/frappe/desk/leaderboard.py b/frappe/desk/leaderboard.py index 91aa2084cc..4800a7d945 100644 --- a/frappe/desk/leaderboard.py +++ b/frappe/desk/leaderboard.py @@ -45,8 +45,6 @@ def get_energy_point_leaderboard(date_range, company=None, field=None, limit=Non for user in energy_point_users: user_id = user["name"] user["name"] = get_fullname(user["name"]) - user["formatted_name"] = '{}'.format( - user_id, get_fullname(user_id) - ) + user["formatted_name"] = f'{get_fullname(user_id)}' return energy_point_users diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index 8132979dff..3ec0338e83 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -283,7 +283,7 @@ def get_open_count(doctype, name, items=None): try: external_links_data_for_d = get_external_links(d, name, links) out["external_links_found"].append(external_links_data_for_d) - except Exception as e: + except Exception: out["external_links_found"].append({"doctype": d, "open_count": 0, "count": 0}) else: external_links_data_for_d = get_external_links(d, name, links) diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index d4189529aa..3003573d81 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -124,7 +124,7 @@ def normalize_result(result, columns): # Convert to list of dicts from list of lists/tuples data = [] column_names = [column["fieldname"] for column in columns] - if result and isinstance(result[0], (list, tuple)): + if result and isinstance(result[0], list | tuple): for row in result: row_obj = {} for idx, column_name in enumerate(column_names): @@ -507,7 +507,7 @@ def get_data_for_custom_field(doctype, field, names=None): filters = {} if names: - if isinstance(names, (str, bytearray)): + if isinstance(names, str | bytearray): names = frappe.json.loads(names) filters.update({"name": ["in", names]}) @@ -659,7 +659,7 @@ def has_match( cell_value = None if isinstance(row, dict): cell_value = row.get(idx) - elif isinstance(row, (list, tuple)): + elif isinstance(row, list | tuple): cell_value = row[idx] if ( @@ -691,10 +691,10 @@ def get_linked_doctypes(columns, data): columns_dict = get_columns_dict(columns) - for idx, col in enumerate(columns): + for idx in range(len(columns)): df = columns_dict[idx] if df.get("fieldtype") == "Link": - if data and isinstance(data[0], (list, tuple)): + if data and isinstance(data[0], list | tuple): linked_doctypes[df["options"]] = idx else: # dict @@ -705,7 +705,7 @@ def get_linked_doctypes(columns, data): for row in data: if row: if len(row) != len(columns_with_value): - if isinstance(row, (list, tuple)): + if isinstance(row, list | tuple): row = enumerate(row) elif isinstance(row, dict): row = row.items() diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index c69542c44c..ae0d915b7c 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -199,7 +199,7 @@ def get_meta_and_docfield(fieldname, data): def update_wildcard_field_param(data): if (isinstance(data.fields, str) and data.fields == "*") or ( - isinstance(data.fields, (list, tuple)) and len(data.fields) == 1 and data.fields[0] == "*" + isinstance(data.fields, list | tuple) and len(data.fields) == 1 and data.fields[0] == "*" ): data.fields = get_permitted_fields(data.doctype, parenttype=data.parenttype) return True @@ -390,10 +390,10 @@ def append_totals_row(data): for row in data: for i in range(len(row)): - if isinstance(row[i], (float, int)): + if isinstance(row[i], float | int): totals[i] = (totals[i] or 0) + row[i] - if not isinstance(totals[0], (int, float)): + if not isinstance(totals[0], int | float): totals[0] = "Total" data.append(totals) @@ -568,7 +568,7 @@ def get_stats(stats, doctype, filters=None): except frappe.db.SQLError: pass - except frappe.db.InternalError as e: + except frappe.db.InternalError: # raised when _user_tags column is added on the fly pass @@ -673,7 +673,7 @@ def get_filters_cond(doctype, filters, conditions, ignore_permissions=None, with for f in filters: if isinstance(f[1], str) and f[1][0] == "!": flt.append([doctype, f[0], "!=", f[1][1:]]) - elif isinstance(f[1], (list, tuple)) and f[1][0].lower() in ( + elif isinstance(f[1], list | tuple) and f[1][0].lower() in ( "=", ">", "<", diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.py b/frappe/email/doctype/auto_email_report/auto_email_report.py index 88cd216e9a..9ec44ab383 100644 --- a/frappe/email/doctype/auto_email_report/auto_email_report.py +++ b/frappe/email/doctype/auto_email_report/auto_email_report.py @@ -321,7 +321,7 @@ def send_daily(): continue try: auto_email_report.send() - except Exception as e: + except Exception: auto_email_report.log_error(f"Failed to send {auto_email_report.name} Auto Email Report") diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index a438af445d..3fa72d4680 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -4,7 +4,6 @@ import email.utils import functools import imaplib -import socket import time from datetime import datetime, timedelta from poplib import error_proto @@ -96,7 +95,15 @@ class EmailAccount(Document): password: DF.Password | None send_notification_to: DF.SmallText | None send_unsubscribe_message: DF.Check - service: DF.Literal["", "GMail", "Sendgrid", "SparkPost", "Yahoo Mail", "Outlook.com", "Yandex.Mail"] + service: DF.Literal[ + "", + "GMail", + "Sendgrid", + "SparkPost", + "Yahoo Mail", + "Outlook.com", + "Yandex.Mail", + ] signature: DF.TextEditor | None smtp_port: DF.Data | None smtp_server: DF.Data | None @@ -191,20 +198,27 @@ class EmailAccount(Document): self.default_incoming = False messages.append( _("{} has been disabled. It can only be enabled if {} is checked.").format( - frappe.bold(_("Default Incoming")), frappe.bold(_("Enable Incoming")) + frappe.bold(_("Default Incoming")), + frappe.bold(_("Enable Incoming")), ) ) if not self.enable_outgoing and self.default_outgoing: self.default_outgoing = False messages.append( _("{} has been disabled. It can only be enabled if {} is checked.").format( - frappe.bold(_("Default Outgoing")), frappe.bold(_("Enable Outgoing")) + frappe.bold(_("Default Outgoing")), + frappe.bold(_("Enable Outgoing")), ) ) if messages: if len(messages) == 1: (as_list, messages) = (0, messages[0]) - frappe.msgprint(messages, as_list=as_list, indicator="orange", title=_("Defaults Updated")) + frappe.msgprint( + messages, + as_list=as_list, + indicator="orange", + title=_("Defaults Updated"), + ) def on_update(self): """Check there is only one default of each type.""" @@ -284,7 +298,11 @@ class EmailAccount(Document): "loginfailed", ] - other_error_codes = ["err[auth]", "errtemporaryerror", "loginviayourwebbrowser"] + other_error_codes = [ + "err[auth]", + "errtemporaryerror", + "loginviayourwebbrowser", + ] all_error_codes = auth_error_codes + other_error_codes @@ -563,7 +581,15 @@ class EmailAccount(Document): seen_status = messages.get("seen_status", {}).get(uid) if self.email_sync_option != "UNSEEN" or seen_status != "SEEN": # only append the emails with status != 'SEEN' if sync option is set to 'UNSEEN' - mails.append(InboundMail(message, self, frappe.safe_decode(uid), seen_status, append_to)) + mails.append( + InboundMail( + message, + self, + frappe.safe_decode(uid), + seen_status, + append_to, + ) + ) if not self.enable_incoming: return [] @@ -618,7 +644,9 @@ class EmailAccount(Document): def send_auto_reply(self, communication, email): """Send auto reply if set.""" - from frappe.core.doctype.communication.email import set_incoming_outgoing_accounts + from frappe.core.doctype.communication.email import ( + set_incoming_outgoing_accounts, + ) if self.enable_auto_reply: set_incoming_outgoing_accounts(communication) @@ -671,7 +699,10 @@ class EmailAccount(Document): if not self.enable_incoming: frappe.throw(_("Automatic Linking can be activated only if Incoming is enabled.")) - if frappe.db.exists("Email Account", {"enable_automatic_linking": 1, "name": ("!=", self.name)}): + if frappe.db.exists( + "Email Account", + {"enable_automatic_linking": 1, "name": ("!=", self.name)}, + ): frappe.throw(_("Automatic Linking can be activated only for one Email Account.")) def append_email_to_sent_folder(self, message): @@ -717,7 +748,9 @@ def notify_unreplied(): """Sends email notifications if there are unreplied Communications and `notify_if_unreplied` is set as true.""" for email_account in frappe.get_all( - "Email Account", "name", filters={"enable_incoming": 1, "notify_if_unreplied": 1} + "Email Account", + "name", + filters={"enable_incoming": 1, "notify_if_unreplied": 1}, ): email_account = frappe.get_doc("Email Account", email_account.name) @@ -774,7 +807,12 @@ def pull(now=False): doctype = frappe.qb.DocType("Email Account") email_accounts = ( frappe.qb.from_(doctype) - .select(doctype.name, doctype.auth_method, doctype.connected_app, doctype.connected_user) + .select( + doctype.name, + doctype.auth_method, + doctype.connected_app, + doctype.connected_user, + ) .where(doctype.enable_incoming == 1) .where(doctype.awaiting_password == 0) .run(as_dict=1) @@ -820,10 +858,9 @@ def pull_from_email_account(email_account): def get_max_email_uid(email_account): - # get maximum uid of emails - max_uid = 1 + """get maximum uid of emails""" - result = frappe.get_all( + if result := frappe.get_all( "Communication", filters={ "communication_medium": "Email", @@ -831,12 +868,9 @@ def get_max_email_uid(email_account): "email_account": email_account, }, fields=["max(uid) as uid"], - ) - - if not result: - return 1 - else: + ): return cint(result[0].get("uid", 0)) + 1 + return 1 def setup_user_email_inbox(email_account, awaiting_password, email_id, enable_outgoing, used_oauth): @@ -868,7 +902,11 @@ def setup_user_email_inbox(email_account, awaiting_password, email_id, enable_ou # check if inbox is alreay configured user_inbox = ( - frappe.db.get_value("User Email", {"email_account": email_account, "parent": user_name}, ["name"]) + frappe.db.get_value( + "User Email", + {"email_account": email_account, "parent": user_name}, + ["name"], + ) or None ) @@ -895,7 +933,11 @@ def remove_user_email_inbox(email_account): if not email_account: return - users = frappe.get_all("User Email", filters={"email_account": email_account}, fields=["parent as name"]) + users = frappe.get_all( + "User Email", + filters={"email_account": email_account}, + fields=["parent as name"], + ) for user in users: doc = frappe.get_doc("User", user.get("name")) diff --git a/frappe/email/doctype/email_account/test_email_account.py b/frappe/email/doctype/email_account/test_email_account.py index 16364104fa..4728881d7e 100644 --- a/frappe/email/doctype/email_account/test_email_account.py +++ b/frappe/email/doctype/email_account/test_email_account.py @@ -413,10 +413,13 @@ class TestEmailAccount(FrappeTestCase): @patch("frappe.email.receive.EmailServer.select_imap_folder", return_value=True) @patch("frappe.email.receive.EmailServer.logout", side_effect=lambda: None) def mocked_get_inbound_mails( - email_account, messages={}, mocked_logout=None, mocked_select_imap_folder=None + email_account, messages=None, mocked_logout=None, mocked_select_imap_folder=None ): from frappe.email.receive import EmailServer + if messages is None: + messages = {} + def get_mocked_messages(**kwargs): return messages.get(kwargs["folder"], {}) @@ -427,7 +430,12 @@ class TestEmailAccount(FrappeTestCase): @patch("frappe.email.receive.EmailServer.select_imap_folder", return_value=True) @patch("frappe.email.receive.EmailServer.logout", side_effect=lambda: None) - def mocked_email_receive(email_account, messages={}, mocked_logout=None, mocked_select_imap_folder=None): + def mocked_email_receive( + email_account, messages=None, mocked_logout=None, mocked_select_imap_folder=None + ): + if messages is None: + messages = {} + def get_mocked_messages(**kwargs): return messages.get(kwargs["folder"], {}) diff --git a/frappe/email/doctype/email_group/email_group.py b/frappe/email/doctype/email_group/email_group.py index a6fafe9a03..8c80a52fcb 100755 --- a/frappe/email/doctype/email_group/email_group.py +++ b/frappe/email/doctype/email_group/email_group.py @@ -105,7 +105,7 @@ def import_from(name, doctype): @frappe.whitelist() def add_subscribers(name, email_list): - if not isinstance(email_list, (list, tuple)): + if not isinstance(email_list, list | tuple): email_list = email_list.replace(",", "\n").split("\n") template = frappe.db.get_value("Email Group", name, "welcome_email_template") diff --git a/frappe/frappeclient.py b/frappe/frappeclient.py index 00d0ef332a..1bee9db571 100644 --- a/frappe/frappeclient.py +++ b/frappe/frappeclient.py @@ -356,7 +356,7 @@ class FrappeClient: def preprocess(self, params): """convert dicts, lists to json""" for key, value in params.items(): - if isinstance(value, (dict, list)): + if isinstance(value, dict | list): params[key] = json.dumps(value) return params diff --git a/frappe/gettext/extractors/navbar.py b/frappe/gettext/extractors/navbar.py index c40790dd41..924d3a4403 100644 --- a/frappe/gettext/extractors/navbar.py +++ b/frappe/gettext/extractors/navbar.py @@ -14,7 +14,7 @@ def extract(fileobj, *args, **kwargs): module = get_module(fileobj.name) if hasattr(module, "standard_navbar_items"): - standard_navbar_items = getattr(module, "standard_navbar_items") + standard_navbar_items = module.standard_navbar_items for nav_item in standard_navbar_items: if label := nav_item.get("item_label"): item_type = nav_item.get("item_type") @@ -29,7 +29,7 @@ def extract(fileobj, *args, **kwargs): ) if hasattr(module, "standard_help_items"): - standard_help_items = getattr(module, "standard_help_items") + standard_help_items = module.standard_help_items for help_item in standard_help_items: if label := help_item.get("item_label"): item_type = nav_item.get("item_type") diff --git a/frappe/installer.py b/frappe/installer.py index d33926690d..682ef4fd7c 100644 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -834,10 +834,10 @@ def partial_restore(sql_file_path, verbose=False): warn = click.style( "Delete the tables you want to restore manually before attempting" - " partial restore operation for PostreSQL databases", + " partial restore operation for PostgreSQL databases", fg="yellow", ) - warnings.warn(warn) + warnings.warn(warn, stacklevel=2) else: click.secho("Unsupported database type", fg="red") return diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py index 031ba18817..edcbba1c3f 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py @@ -106,7 +106,7 @@ def take_backup_to_dropbox(retry_count=0, upload_db_backup=True): if isinstance(error_log, str): error_message = error_log + "\n" + frappe.get_traceback() else: - file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)] + file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log, strict=False)] error_message = "\n".join(file_and_error) + "\n" + frappe.get_traceback() send_email(False, "Dropbox", "Dropbox Settings", "send_notifications_to", error_message) diff --git a/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py b/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py index 1fcda3e077..92918e8197 100644 --- a/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py +++ b/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py @@ -489,7 +489,7 @@ class LDAP_TestCase: @mock_ldap_connection def test_get_ldap_attributes(self): method_return = self.test_class.get_ldap_attributes() - self.assertTrue(type(method_return) is list) + self.assertTrue(isinstance(method_return, list)) @mock_ldap_connection def test_fetch_ldap_groups(self): @@ -599,7 +599,7 @@ class LDAP_TestCase: test_ldap_entry = self.connection.entries[0] method_return = self.test_class.convert_ldap_entry_to_dict(test_ldap_entry) - self.assertTrue(type(method_return) is dict) # must be dict + self.assertTrue(isinstance(method_return, dict)) # must be dict self.assertTrue(len(method_return) == 6) # there are 6 fields in mock_ldap for use diff --git a/frappe/integrations/frappe_providers/frappecloud.py b/frappe/integrations/frappe_providers/frappecloud.py index bae811d41d..f276004427 100644 --- a/frappe/integrations/frappe_providers/frappecloud.py +++ b/frappe/integrations/frappe_providers/frappecloud.py @@ -12,11 +12,7 @@ def frappecloud_migrator(local_site): request = requests.get(request_url) if request.status_code / 100 != 2: - print( - "Request exitted with Status Code: {}\nPayload: {}".format( - request.status_code, html2text(request.text) - ) - ) + print(f"Request exited with Status Code: {request.status_code}\nPayload: {html2text(request.text)}") click.secho( "Some errors occurred while recovering the migration script. Please contact us @ Frappe Cloud if this issue persists", fg="yellow", diff --git a/frappe/integrations/google_oauth.py b/frappe/integrations/google_oauth.py index 19d6035f3a..c3a154f0e9 100644 --- a/frappe/integrations/google_oauth.py +++ b/frappe/integrations/google_oauth.py @@ -39,7 +39,7 @@ class GoogleOAuth: self.domain = domain.lower() self.scopes = ( " ".join(_SCOPES[self.domain]) - if isinstance(_SCOPES[self.domain], (list, tuple)) + if isinstance(_SCOPES[self.domain], list | tuple) else _SCOPES[self.domain] ) diff --git a/frappe/integrations/offsite_backup_utils.py b/frappe/integrations/offsite_backup_utils.py index da9f35b146..8cd29d5ecc 100644 --- a/frappe/integrations/offsite_backup_utils.py +++ b/frappe/integrations/offsite_backup_utils.py @@ -29,11 +29,11 @@ def send_email(success, service_name, doctype, email_field, error_status=None): ) else: subject = "[Warning] Backup Upload Failed" - message = """ + message = f"""

Backup Upload Failed!

-

Oops, your automated backup to {} failed.

-

Error message: {}

-

Please contact your system manager for more information.

""".format(service_name, error_status) +

Oops, your automated backup to {service_name} failed.

+

Error message: {error_status}

+

Please contact your system manager for more information.

""" frappe.sendmail(recipients=recipients, subject=subject, message=message) diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index ca6065c577..47fec33013 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -155,5 +155,5 @@ def get_json(obj): def json_handler(obj): - if isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)): + if isinstance(obj, datetime.date | datetime.timedelta | datetime.datetime): return str(obj) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 2c7933b1d7..943fcfae10 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -217,7 +217,7 @@ class BaseDocument: value = self.__dict__.get(key, default) - if limit and isinstance(value, (list, tuple)) and len(value) > limit: + if limit and isinstance(value, list | tuple) and len(value) > limit: value = value[:limit] return value @@ -396,7 +396,7 @@ class BaseDocument: value = None if convert_dates_to_str and isinstance( - value, (datetime.datetime, datetime.date, datetime.time, datetime.timedelta) + value, datetime.datetime | datetime.date | datetime.time | datetime.timedelta ): value = str(value) @@ -1189,7 +1189,7 @@ class BaseDocument: if not doc: doc = getattr(self, "parent_doc", None) or self - if (absolute_value or doc.get("absolute_value")) and isinstance(val, (int, float)): + if (absolute_value or doc.get("absolute_value")) and isinstance(val, int | float): val = abs(self.get(fieldname)) return format_value(val, df=df, doc=doc, currency=currency, format=format) @@ -1297,7 +1297,7 @@ def _filter(data, filters, limit=None): for f in filters: fval = filters[f] - if not isinstance(fval, (tuple, list)): + if not isinstance(fval, tuple | list): if fval is True: fval = ("not None", fval) elif fval is False: diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 23a46425c5..da4dd4f112 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -222,15 +222,12 @@ class DatabaseQuery: if frappe.db.db_type == "postgres" and args.order_by and args.group_by: args = self.prepare_select_args(args) - query = ( - """select %(fields)s - from %(tables)s - %(conditions)s - %(group_by)s - %(order_by)s - %(limit)s""" - % args - ) + query = """select {fields} + from {tables} + {conditions} + {group_by} + {order_by} + {limit}""".format(**args) return frappe.db.sql( query, @@ -1270,7 +1267,7 @@ def get_between_date_filter(value, df=None): from_date = frappe.utils.nowdate() to_date = frappe.utils.nowdate() - if value and isinstance(value, (list, tuple)): + if value and isinstance(value, list | tuple): if len(value) >= 1: from_date = value[0] if len(value) >= 2: diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index 5967e9c5c9..c6cce21a06 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -354,8 +354,8 @@ def check_if_doc_is_dynamically_linked(doc, method="Delete"): def raise_link_exists_exception(doc, reference_doctype, reference_docname, row=""): - doc_link = '{1}'.format(doc.doctype, doc.name) - reference_link = '{1}'.format(reference_doctype, reference_docname) + doc_link = f'{doc.name}' + reference_link = f'{reference_docname}' # hack to display Single doctype only once in message if reference_doctype == reference_docname: @@ -407,12 +407,12 @@ def clear_references( reference_name_field="reference_name", ): frappe.db.sql( - """update - `tab{0}` + f"""update + `tab{doctype}` set - {1}=NULL, {2}=NULL + {reference_doctype_field}=NULL, {reference_name_field}=NULL where - {1}=%s and {2}=%s""".format(doctype, reference_doctype_field, reference_name_field), # nosec + {reference_doctype_field}=%s and {reference_name_field}=%s""", # nosec (reference_doctype, reference_name), ) diff --git a/frappe/model/document.py b/frappe/model/document.py index 48c37bd8e5..090008492e 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -161,7 +161,7 @@ class Document(BaseDocument): else: get_value_kwargs = {"for_update": self.flags.for_update, "as_dict": True} - if not isinstance(self.name, (dict, list)): + if not isinstance(self.name, dict | list): get_value_kwargs["order_by"] = None d = frappe.db.get_value( @@ -883,7 +883,7 @@ class Document(BaseDocument): if not missing: return - for fieldname, msg in missing: + for idx, msg in missing: # noqa: B007 msgprint(msg) if frappe.flags.print_messages: @@ -1252,7 +1252,7 @@ class Document(BaseDocument): doc_to_compare = frappe.get_doc(self.doctype, amended_from) version = frappe.new_doc("Version") - if is_useful_diff := version.update_version_info(doc_to_compare, self): + if version.update_version_info(doc_to_compare, self): version.insert(ignore_permissions=True) if not frappe.flags.in_migrate: @@ -1540,7 +1540,7 @@ class Document(BaseDocument): file_lock.delete_lock(signature) lock_exists = False if timeout: - for i in range(timeout): + for _ in range(timeout): time.sleep(1) if not file_lock.lock_exists(signature): lock_exists = False diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 7a205cf507..8dca6b32bf 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -147,7 +147,7 @@ class Meta(Document): def serialize(doc): out = {} for key, value in doc.__dict__.items(): - if isinstance(value, (list, tuple)): + if isinstance(value, list | tuple): if not value or not isinstance(value[0], BaseDocument): # non standard list object, skip continue @@ -155,7 +155,7 @@ class Meta(Document): value = [serialize(d) for d in value] if (not no_nulls and value is None) or isinstance( - value, (str, int, float, datetime, list, tuple) + value, str | int | float | datetime | list | tuple ): out[key] = value @@ -713,9 +713,7 @@ class Meta(Document): module_name, "doctype", doctype, "templates", doctype + suffix + ".html" ) if os.path.exists(template_path): - return "{module_name}/doctype/{doctype_name}/templates/{doctype_name}{suffix}.html".format( - module_name=module_name, doctype_name=doctype, suffix=suffix - ) + return f"{module_name}/doctype/{doctype}/templates/{doctype}{suffix}.html" return None def is_nested_set(self): diff --git a/frappe/model/naming.py b/frappe/model/naming.py index 5a0e23159f..15e4c549e6 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -465,12 +465,10 @@ def append_number_if_name_exists(doctype, value, fieldname="name", separator="-" if exists: last = frappe.db.sql( - """SELECT `{fieldname}` FROM `tab{doctype}` - WHERE `{fieldname}` {regex_character} %s + f"""SELECT `{fieldname}` FROM `tab{doctype}` + WHERE `{fieldname}` {frappe.db.REGEX_CHARACTER} %s ORDER BY length({fieldname}) DESC, - `{fieldname}` DESC LIMIT 1""".format( - doctype=doctype, fieldname=fieldname, regex_character=frappe.db.REGEX_CHARACTER - ), + `{fieldname}` DESC LIMIT 1""", regex, ) diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index 42864880a0..b535331c23 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -47,7 +47,7 @@ def update_document_title( # TODO: omit this after runtime type checking (ref: https://github.com/frappe/frappe/pull/14927) for obj in [docname, updated_title, updated_name]: - if not isinstance(obj, (str, NoneType)): + if not isinstance(obj, str | NoneType): frappe.throw(f"{obj=} must be of type str or None") # handle bad API usages diff --git a/frappe/model/utils/__init__.py b/frappe/model/utils/__init__.py index d0015101b1..7d8a389ec9 100644 --- a/frappe/model/utils/__init__.py +++ b/frappe/model/utils/__init__.py @@ -3,7 +3,6 @@ import re import frappe -from frappe import _ from frappe.build import html_to_js_template from frappe.utils import cstr from frappe.utils.caching import site_cache @@ -30,9 +29,8 @@ def set_default(doc, key): frappe.db.set(doc, "is_default", 1) frappe.db.sql( - """update `tab%s` set `is_default`=0 - where `%s`=%s and name!=%s""" - % (doc.doctype, key, "%s", "%s"), + """update `tab{}` set `is_default`=0 + where `{}`={} and name!={}""".format(doc.doctype, key, "%s", "%s"), (doc.get(key), doc.name), ) @@ -62,7 +60,7 @@ def render_include(content): content = cstr(content) # try 5 levels of includes - for i in range(5): + for _ in range(5): if "{% include" in content: paths = INCLUDE_DIRECTIVE_PATTERN.findall(content) if not paths: diff --git a/frappe/model/utils/rename_field.py b/frappe/model/utils/rename_field.py index e3b0835ddd..23c934da74 100644 --- a/frappe/model/utils/rename_field.py +++ b/frappe/model/utils/rename_field.py @@ -27,9 +27,8 @@ def rename_field(doctype, old_fieldname, new_fieldname, validate=True): if new_field.fieldtype in table_fields: # change parentfield of table mentioned in options frappe.db.sql( - """update `tab%s` set parentfield=%s - where parentfield=%s""" - % (new_field.options.split("\n", 1)[0], "%s", "%s"), + """update `tab{}` set parentfield={} + where parentfield={}""".format(new_field.options.split("\n", 1)[0], "%s", "%s"), (new_fieldname, old_fieldname), ) @@ -142,9 +141,8 @@ def update_users_report_view_settings(doctype, ref_fieldname, new_fieldname): if columns_modified: frappe.db.sql( - """update `tabDefaultValue` set defvalue=%s - where defkey=%s""" - % ("%s", "%s"), + """update `tabDefaultValue` set defvalue={} + where defkey={}""".format("%s", "%s"), (json.dumps(new_columns), key), ) diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py index 56f3956f6f..52379892d0 100644 --- a/frappe/modules/import_file.py +++ b/frappe/modules/import_file.py @@ -38,7 +38,7 @@ ignore_doctypes = [""] def import_files(module, dt=None, dn=None, force=False, pre_process=None, reset_permissions=False): - if type(module) is list: + if isinstance(module, list): return [ import_file( m[0], @@ -209,11 +209,7 @@ def import_doc( docdict["__islocal"] = 1 controller = get_controller(docdict["doctype"]) - if ( - controller - and hasattr(controller, "prepare_for_import") - and callable(getattr(controller, "prepare_for_import")) - ): + if controller and hasattr(controller, "prepare_for_import") and callable(controller.prepare_for_import): controller.prepare_for_import(docdict) doc = frappe.get_doc(docdict) diff --git a/frappe/parallel_test_runner.py b/frappe/parallel_test_runner.py index 8f101be883..b0d3244e18 100644 --- a/frappe/parallel_test_runner.py +++ b/frappe/parallel_test_runner.py @@ -143,7 +143,7 @@ def split_by_weight(work, weights, chunk_count): chunk_no = 0 chunk_weight = 0 - for task, weight in zip(work, weights): + for task, weight in zip(work, weights, strict=False): if chunk_weight > expected_weight: chunk_weight = 0 chunk_no += 1 diff --git a/frappe/patches/v11_0/delete_duplicate_user_permissions.py b/frappe/patches/v11_0/delete_duplicate_user_permissions.py index a8bb291769..27af1e98c7 100644 --- a/frappe/patches/v11_0/delete_duplicate_user_permissions.py +++ b/frappe/patches/v11_0/delete_duplicate_user_permissions.py @@ -12,7 +12,7 @@ def execute(): for record in duplicateRecords: frappe.db.sql( - """delete from `tabUser Permission` - where allow=%s and user=%s and for_value=%s limit {}""".format(record.count - 1), + f"""delete from `tabUser Permission` + where allow=%s and user=%s and for_value=%s limit {record.count - 1}""", (record.allow, record.user, record.for_value), ) diff --git a/frappe/patches/v11_0/update_list_user_settings.py b/frappe/patches/v11_0/update_list_user_settings.py index 5cbcd3bc0a..f90871af27 100644 --- a/frappe/patches/v11_0/update_list_user_settings.py +++ b/frappe/patches/v11_0/update_list_user_settings.py @@ -12,8 +12,8 @@ def execute(): for user in users: # get user_settings for each user settings = frappe.db.sql( - "select * from `__UserSettings` \ - where user={}".format(frappe.db.escape(user.user)), + f"select * from `__UserSettings` \ + where user={frappe.db.escape(user.user)}", as_dict=True, ) diff --git a/frappe/patches/v12_0/move_email_and_phone_to_child_table.py b/frappe/patches/v12_0/move_email_and_phone_to_child_table.py index 7511a2ee1d..e1fcb72e21 100644 --- a/frappe/patches/v12_0/move_email_and_phone_to_child_table.py +++ b/frappe/patches/v12_0/move_email_and_phone_to_child_table.py @@ -22,7 +22,6 @@ def execute(): phone_values = [] for count, contact_detail in enumerate(contact_details): phone_counter = 1 - is_primary = 1 if contact_detail.email_id: email_values.append( ( diff --git a/frappe/patches/v12_0/replace_null_values_in_tables.py b/frappe/patches/v12_0/replace_null_values_in_tables.py index 1dc8d964a1..617e9886f6 100644 --- a/frappe/patches/v12_0/replace_null_values_in_tables.py +++ b/frappe/patches/v12_0/replace_null_values_in_tables.py @@ -18,7 +18,7 @@ def execute(): update_column_table_map.setdefault(field.TABLE_NAME, []) update_column_table_map[field.TABLE_NAME].append( - "`{fieldname}`=COALESCE(`{fieldname}`, 0)".format(fieldname=field.COLUMN_NAME) + f"`{field.COLUMN_NAME}`=COALESCE(`{field.COLUMN_NAME}`, 0)" ) for table in frappe.db.get_tables(): diff --git a/frappe/patches/v13_0/update_date_filters_in_user_settings.py b/frappe/patches/v13_0/update_date_filters_in_user_settings.py index 6565641d9b..030ea3936d 100644 --- a/frappe/patches/v13_0/update_date_filters_in_user_settings.py +++ b/frappe/patches/v13_0/update_date_filters_in_user_settings.py @@ -9,12 +9,12 @@ def execute(): for user in users: user_settings = frappe.db.sql( - """ + f""" select * from `__UserSettings` where - user='{user}' - """.format(user=user.user), + user='{user.user}' + """, as_dict=True, ) diff --git a/frappe/permissions.py b/frappe/permissions.py index cb13ca45af..97e31255ef 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -127,7 +127,7 @@ def has_permission( meta = frappe.get_meta(doctype) if doc: - if isinstance(doc, (str, int)): + if isinstance(doc, str | int): doc = frappe.get_doc(meta.name, doc) perm = get_doc_permissions(doc, user=user, ptype=ptype, debug=debug).get(ptype) if not perm: diff --git a/frappe/recorder.py b/frappe/recorder.py index a0b4c17880..974f98b371 100644 --- a/frappe/recorder.py +++ b/frappe/recorder.py @@ -81,7 +81,7 @@ def get_current_stack_frames(): try: current = inspect.currentframe() frames = inspect.getouterframes(current, context=10) - for frame, filename, lineno, function, context, index in list(reversed(frames))[:-2]: + for frame, filename, lineno, function, context, index in list(reversed(frames))[:-2]: # noqa: B007 if "/apps/" in filename or SERVER_SCRIPT_FILE_PREFIX in filename: yield { "filename": TRACEBACK_PATH_PATTERN.sub("", filename), diff --git a/frappe/social/doctype/energy_point_log/energy_point_log.py b/frappe/social/doctype/energy_point_log/energy_point_log.py index 8c58026774..a124050305 100644 --- a/frappe/social/doctype/energy_point_log/energy_point_log.py +++ b/frappe/social/doctype/energy_point_log/energy_point_log.py @@ -257,7 +257,7 @@ def get_user_energy_and_review_points(user=None, from_date=None, as_dict=True): values.from_date = from_date points_list = frappe.db.sql( - """ + f""" SELECT SUM(CASE WHEN `type` != 'Review' THEN `points` ELSE 0 END) AS energy_points, SUM(CASE WHEN `type` = 'Review' THEN `points` ELSE 0 END) AS review_points, @@ -271,7 +271,7 @@ def get_user_energy_and_review_points(user=None, from_date=None, as_dict=True): {conditions} GROUP BY `user` ORDER BY `energy_points` DESC - """.format(conditions=conditions, given_points_condition=given_points_condition), + """, values=values, as_dict=1, ) diff --git a/frappe/social/doctype/energy_point_rule/energy_point_rule.py b/frappe/social/doctype/energy_point_rule/energy_point_rule.py index 712b1f7b0a..6776e28aad 100644 --- a/frappe/social/doctype/energy_point_rule/energy_point_rule.py +++ b/frappe/social/doctype/energy_point_rule/energy_point_rule.py @@ -77,7 +77,7 @@ class EnergyPointRule(Document): {"points": points, "user": user, "rule": rule}, self.apply_only_once, ) - except Exception as e: + except Exception: self.log_error("Energy points failed") def rule_condition_satisfied(self, doc): diff --git a/frappe/test_runner.py b/frappe/test_runner.py index 62e5dd599a..4001aa9130 100644 --- a/frappe/test_runner.py +++ b/frappe/test_runner.py @@ -215,7 +215,7 @@ def run_tests_for_doctype( junit_xml_output=False, ): modules = [] - if not isinstance(doctypes, (list, tuple)): + if not isinstance(doctypes, list | tuple): doctypes = [doctypes] for doctype in doctypes: @@ -268,7 +268,7 @@ def _run_unittest( test_suite = unittest.TestSuite() - if not isinstance(modules, (list, tuple)): + if not isinstance(modules, list | tuple): modules = [modules] for module in modules: diff --git a/frappe/tests/test_api.py b/frappe/tests/test_api.py index 61e76b213d..05eb71f696 100644 --- a/frappe/tests/test_api.py +++ b/frappe/tests/test_api.py @@ -54,7 +54,9 @@ def patch_request_header(key, *args, **kwargs): class ThreadWithReturnValue(Thread): - def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, *, site=None): + def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, site=None): + if kwargs is None: + kwargs = {} Thread.__init__(self, group, target, name, args, kwargs) self._return = None self.site = site or _site diff --git a/frappe/tests/test_caching.py b/frappe/tests/test_caching.py index 950a07ef94..ccc44bbcfc 100644 --- a/frappe/tests/test_caching.py +++ b/frappe/tests/test_caching.py @@ -15,7 +15,7 @@ register_with_external_service = MagicMock(return_value=True) def request_specific_api(a: list | tuple | dict | int, b: int) -> int: # API that takes very long to return a result todays_value = external_service() - if not isinstance(a, (int, float)): + if not isinstance(a, int | float): a = 1 return a**b * todays_value @@ -44,7 +44,9 @@ class TestCachingUtils(FrappeTestCase): frappe.get_last_doc("DocType"), frappe._dict(), ] - same_output_received = lambda: all([x for x in set(retval) if x == retval[0]]) + + def same_output_received(): + return all([x for x in set(retval) if x == retval[0]]) # ensure that external service was called only once # thereby return value of request_specific_api is cached diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 35ba845d5f..1bdf3b5430 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -2,7 +2,6 @@ # License: MIT. See LICENSE import datetime -import inspect from math import ceil from random import choice from unittest.mock import patch @@ -17,7 +16,7 @@ from frappe.query_builder import Field from frappe.query_builder.functions import Concat_ws from frappe.tests.test_query_builder import db_type_is, run_only_if from frappe.tests.utils import FrappeTestCase -from frappe.utils import add_days, cint, now, random_string, set_request +from frappe.utils import add_days, now, random_string, set_request from frappe.utils.testutils import clear_custom_fields @@ -437,7 +436,7 @@ class TestDB(FrappeTestCase): frappe.db.MAX_WRITES_PER_TRANSACTION = 1 note = frappe.get_last_doc("ToDo") note.description = "changed" - with self.assertRaises(frappe.TooManyWritesError) as tmw: + with self.assertRaises(frappe.TooManyWritesError): note.save() frappe.db.MAX_WRITES_PER_TRANSACTION = Database.MAX_WRITES_PER_TRANSACTION diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index 89c29e9892..862e49bef4 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -57,7 +57,11 @@ class TestDBQuery(FrappeTestCase): db_query = DatabaseQuery("DocType") add_custom_field("DocType", "test_tab_field", "Data") - db_query.fields = ["tabNote.creation", "test_tab_field", "tabDocType.test_tab_field"] + db_query.fields = [ + "tabNote.creation", + "test_tab_field", + "tabDocType.test_tab_field", + ] db_query.extract_tables() self.assertIn("`tabNote`", db_query.tables) self.assertIn("`tabDocType`", db_query.tables) @@ -148,7 +152,10 @@ class TestDBQuery(FrappeTestCase): frappe.get_doc( doctype="Parent DocType 1", title="test", - child=[{"title": "parent 1 child record 1"}, {"title": "parent 1 child record 2"}], + child=[ + {"title": "parent 1 child record 1"}, + {"title": "parent 1 child record 2"}, + ], __newname="test_parent", ).insert(ignore_if_duplicate=True) frappe.get_doc( @@ -295,7 +302,8 @@ class TestDBQuery(FrappeTestCase): # if both from and to_date values are passed data = DatabaseQuery("Event").execute( - filters={"starts_on": ["between", ["2016-07-06", "2016-07-07"]]}, fields=["name"] + filters={"starts_on": ["between", ["2016-07-06", "2016-07-07"]]}, + fields=["name"], ) self.assertIn({"name": event2.name}, data) @@ -316,7 +324,8 @@ class TestDBQuery(FrappeTestCase): # test between is formatted for creation column data = DatabaseQuery("Event").execute( - filters={"creation": ["between", ["2016-07-06", "2016-07-07"]]}, fields=["name"] + filters={"creation": ["between", ["2016-07-06", "2016-07-07"]]}, + fields=["name"], ) def test_between_filters_date_bounds(self): @@ -368,7 +377,10 @@ class TestDBQuery(FrappeTestCase): self.assertRaises( frappe.DataError, DatabaseQuery("DocType").execute, - fields=["name", "issingle, IF(issingle=1, (select name from tabUser), count(name))"], + fields=[ + "name", + "issingle, IF(issingle=1, (select name from tabUser), count(name))", + ], limit_start=0, limit_page_length=1, ) @@ -392,7 +404,10 @@ class TestDBQuery(FrappeTestCase): self.assertRaises( frappe.DataError, DatabaseQuery("DocType").execute, - fields=["name", "issingle, IF(issingle=1, (SELECT name from tabUser), count(*))"], + fields=[ + "name", + "issingle, IF(issingle=1, (SELECT name from tabUser), count(*))", + ], limit_start=0, limit_page_length=1, ) @@ -466,14 +481,20 @@ class TestDBQuery(FrappeTestCase): self.assertTrue("_relevance" in data[0]) data = DatabaseQuery("DocType").execute( - fields=["name", "issingle", "date(creation) as creation"], limit_start=0, limit_page_length=1 + fields=["name", "issingle", "date(creation) as creation"], + limit_start=0, + limit_page_length=1, ) self.assertTrue("creation" in data[0]) if frappe.db.db_type != "postgres": # datediff function does not exist in postgres data = DatabaseQuery("DocType").execute( - fields=["name", "issingle", "datediff(modified, creation) as date_diff"], + fields=[ + "name", + "issingle", + "datediff(modified, creation) as date_diff", + ], limit_start=0, limit_page_length=1, ) @@ -481,14 +502,22 @@ class TestDBQuery(FrappeTestCase): with self.assertRaises(frappe.DataError): DatabaseQuery("DocType").execute( - fields=["name", "issingle", "if (issingle=1, (select name from tabUser), count(name))"], + fields=[ + "name", + "issingle", + "if (issingle=1, (select name from tabUser), count(name))", + ], limit_start=0, limit_page_length=1, ) with self.assertRaises(frappe.DataError): DatabaseQuery("DocType").execute( - fields=["name", "issingle", "if(issingle=1, (select name from tabUser), count(name))"], + fields=[ + "name", + "issingle", + "if(issingle=1, (select name from tabUser), count(name))", + ], limit_start=0, limit_page_length=1, ) @@ -578,7 +607,10 @@ class TestDBQuery(FrappeTestCase): DatabaseQuery("DocType").execute, fields=["name"], filters={"editable_grid,": 1}, - or_filters=[["DocType", "istable", "=", 1], ["DocType", "beta and 1=1", "=", 0]], + or_filters=[ + ["DocType", "istable", "=", 1], + ["DocType", "beta and 1=1", "=", 0], + ], limit_start=0, limit_page_length=1, ) @@ -600,13 +632,18 @@ class TestDBQuery(FrappeTestCase): self.assertTrue("Role Permission for Page and Report" in [d["name"] for d in out]) out = DatabaseQuery("DocType").execute( - fields=["name"], filters={"track_changes": 1, "module": "Core"}, order_by="creation" + fields=["name"], + filters={"track_changes": 1, "module": "Core"}, + order_by="creation", ) self.assertTrue("File" in [d["name"] for d in out]) out = DatabaseQuery("DocType").execute( fields=["name"], - filters=[["DocType", "ifnull(track_changes, 0)", "=", 0], ["DocType", "module", "=", "Core"]], + filters=[ + ["DocType", "ifnull(track_changes, 0)", "=", 0], + ["DocType", "module", "=", "Core"], + ], order_by="creation", ) self.assertTrue("DefaultValue" in [d["name"] for d in out]) @@ -743,7 +780,7 @@ class TestDBQuery(FrappeTestCase): def test_set_field_tables(self): # Tests _in_standard_sql_methods method in test_set_field_tables # The following query will break if the above method is broken - data = frappe.db.get_list( + frappe.db.get_list( "Web Form", filters=[["Web Form Field", "reqd", "=", 1]], fields=["count(*) as count"], @@ -755,7 +792,7 @@ class TestDBQuery(FrappeTestCase): try: frappe.get_list("Prepared Report", ["*"]) frappe.get_list("Scheduled Job Type", ["*"]) - except Exception as e: + except Exception: print(frappe.get_traceback()) self.fail("get_list not working with virtual field") @@ -805,21 +842,30 @@ class TestDBQuery(FrappeTestCase): def test_permlevel_fields(self): with setup_patched_blog_post(), setup_test_user(set_user=True): data = frappe.get_list( - "Blog Post", filters={"published": 1}, fields=["name", "published"], limit=1 + "Blog Post", + filters={"published": 1}, + fields=["name", "published"], + limit=1, ) self.assertFalse("published" in data[0]) self.assertTrue("name" in data[0]) self.assertEqual(len(data[0]), 1) data = frappe.get_list( - "Blog Post", filters={"published": 1}, fields=["name", "`published`"], limit=1 + "Blog Post", + filters={"published": 1}, + fields=["name", "`published`"], + limit=1, ) self.assertFalse("published" in data[0]) self.assertTrue("name" in data[0]) self.assertEqual(len(data[0]), 1) data = frappe.get_list( - "Blog Post", filters={"published": 1}, fields=["name", "`tabBlog Post`.`published`"], limit=1 + "Blog Post", + filters={"published": 1}, + fields=["name", "`tabBlog Post`.`published`"], + limit=1, ) self.assertFalse("published" in data[0]) self.assertTrue("name" in data[0]) @@ -836,13 +882,19 @@ class TestDBQuery(FrappeTestCase): self.assertEqual(len(data[0]), 1) data = frappe.get_list( - "Blog Post", filters={"published": 1}, fields=["name", "MAX(`published`)"], limit=1 + "Blog Post", + filters={"published": 1}, + fields=["name", "MAX(`published`)"], + limit=1, ) self.assertTrue("name" in data[0]) self.assertEqual(len(data[0]), 1) data = frappe.get_list( - "Blog Post", filters={"published": 1}, fields=["name", "LAST(published)"], limit=1 + "Blog Post", + filters={"published": 1}, + fields=["name", "LAST(published)"], + limit=1, ) self.assertTrue("name" in data[0]) self.assertEqual(len(data[0]), 1) @@ -858,12 +910,20 @@ class TestDBQuery(FrappeTestCase): self.assertEqual(len(data[0]), 2) data = frappe.get_list( - "Blog Post", filters={"published": 1}, fields=["name", "now() abhi"], limit=1 + "Blog Post", + filters={"published": 1}, + fields=["name", "now() abhi"], + limit=1, ) self.assertIsInstance(data[0]["abhi"], datetime.datetime) self.assertEqual(len(data[0]), 2) - data = frappe.get_list("Blog Post", filters={"published": 1}, fields=["name", "'LABEL'"], limit=1) + data = frappe.get_list( + "Blog Post", + filters={"published": 1}, + fields=["name", "'LABEL'"], + limit=1, + ) self.assertTrue("name" in data[0]) self.assertTrue("LABEL" in data[0].values()) self.assertEqual(len(data[0]), 2) @@ -892,7 +952,11 @@ class TestDBQuery(FrappeTestCase): data = frappe.get_list( "Blog Post", - fields=["name", "blogger.full_name as blogger_full_name", "blog_category.description"], + fields=[ + "name", + "blogger.full_name as blogger_full_name", + "blog_category.description", + ], limit=1, ) self.assertTrue("name" in data[0]) @@ -906,7 +970,11 @@ class TestDBQuery(FrappeTestCase): dt = new_doctype("autoinc_dt_test", autoname="autoincrement").insert(ignore_permissions=True) query = DatabaseQuery("autoinc_dt_test").execute( - fields=["locate('1', `tabautoinc_dt_test`.`name`)", "name", "locate('1', name)"], + fields=[ + "locate('1', `tabautoinc_dt_test`.`name`)", + "name", + "locate('1', name)", + ], filters={"name": 1}, run=False, ) @@ -929,7 +997,9 @@ class TestDBQuery(FrappeTestCase): frappe.delete_doc_if_exists("DocType", "table_dt") table_dt = new_doctype( - "table_dt", istable=1, fields=[{"label": "1field", "fieldname": "2field", "fieldtype": "Data"}] + "table_dt", + istable=1, + fields=[{"label": "1field", "fieldname": "2field", "fieldtype": "Data"}], ).insert() dt = new_doctype( @@ -974,7 +1044,9 @@ class TestDBQuery(FrappeTestCase): table_dt.delete() def test_permission_query_condition(self): - from frappe.desk.doctype.dashboard_settings.dashboard_settings import create_dashboard_settings + from frappe.desk.doctype.dashboard_settings.dashboard_settings import ( + create_dashboard_settings, + ) self.doctype = "Dashboard Settings" self.user = "test'5@example.com" @@ -984,11 +1056,11 @@ class TestDBQuery(FrappeTestCase): create_dashboard_settings(self.user) dashboard_settings = frappe.db.sql( - """ + f""" SELECT name FROM `tabDashboard Settings` - WHERE {condition} - """.format(condition=permission_query_conditions), + WHERE {permission_query_conditions} + """, as_dict=1, )[0] @@ -1006,7 +1078,10 @@ class TestDBQuery(FrappeTestCase): def get_list(args): ... - with patch("frappe.controllers", new={frappe.local.site: {"Virtual DocType": VirtualDocType}}): + with patch( + "frappe.controllers", + new={frappe.local.site: {"Virtual DocType": VirtualDocType}}, + ): VirtualDocType.get_list = MagicMock() frappe.get_all("Virtual DocType", filters={"name": "test"}, fields=["name"], limit=1) @@ -1120,7 +1195,11 @@ class TestReportView(FrappeTestCase): ) list_filter_response = execute_cmd("frappe.desk.reportview.get_count") frappe.local.form_dict = frappe._dict( - {"doctype": "DocType", "filters": {"show_title_field_in_link": 1}, "distinct": "true"} + { + "doctype": "DocType", + "filters": {"show_title_field_in_link": 1}, + "distinct": "true", + } ) dict_filter_response = execute_cmd("frappe.desk.reportview.get_count") self.assertIsInstance(list_filter_response, int) diff --git a/frappe/tests/test_oauth20.py b/frappe/tests/test_oauth20.py index 8bf0ccdde7..83c5625bff 100644 --- a/frappe/tests/test_oauth20.py +++ b/frappe/tests/test_oauth20.py @@ -316,7 +316,7 @@ class TestOAuth20(FrappeRequestTestCase): frappe.db.commit() def test_openid_code_id_token(self): - client = update_client_for_auth_code_grant(self.client_id) + update_client_for_auth_code_grant(self.client_id) nonce = frappe.generate_hash() # Go to Authorize url diff --git a/frappe/tests/test_patches.py b/frappe/tests/test_patches.py index 3b3b9f1702..b483b6d322 100644 --- a/frappe/tests/test_patches.py +++ b/frappe/tests/test_patches.py @@ -164,7 +164,7 @@ def check_patch_files(app): missing_patches.append(module) if missing_patches: - raise Exception(f"Patches missing in patch.txt: \n" + "\n".join(missing_patches)) + raise Exception("Patches missing in patch.txt: \n" + "\n".join(missing_patches)) def _get_dotted_path(file: Path, app) -> str: diff --git a/frappe/tests/test_perf.py b/frappe/tests/test_perf.py index c0796809c8..91e8c5c890 100644 --- a/frappe/tests/test_perf.py +++ b/frappe/tests/test_perf.py @@ -145,7 +145,7 @@ class TestPerformance(FrappeTestCase): self.assertGreaterEqual( rps, EXPECTED_RPS * (1 - FAILURE_THREASHOLD), - f"Possible performance regression in basic /api/Resource list requests", + "Possible performance regression in basic /api/Resource list requests", ) def test_homepage_resolver(self): diff --git a/frappe/tests/test_query_report.py b/frappe/tests/test_query_report.py index 8d47a846bb..5b693a9556 100644 --- a/frappe/tests/test_query_report.py +++ b/frappe/tests/test_query_report.py @@ -3,7 +3,6 @@ import frappe import frappe.utils -from frappe.core.doctype.doctype.test_doctype import new_doctype from frappe.desk.query_report import build_xlsx_data, export_query, run from frappe.tests.utils import FrappeTestCase from frappe.utils.xlsxutils import make_xlsx @@ -138,7 +137,7 @@ class TestQueryReport(FrappeTestCase): {"label": "First Name", "fieldname": "first_name", "fieldtype": "Data"}, {"label": "Last Name", "fieldname": "last_name", "fieldtype": "Data"}, ] - docA = frappe.get_doc( + frappe.get_doc( { "doctype": "DocType", "name": "Doc A", @@ -150,7 +149,7 @@ class TestQueryReport(FrappeTestCase): } ).insert(ignore_if_duplicate=True) - docB = frappe.get_doc( + frappe.get_doc( { "doctype": "DocType", "name": "Doc B", diff --git a/frappe/tests/test_recorder.py b/frappe/tests/test_recorder.py index e2ff7e1ab4..57393b0238 100644 --- a/frappe/tests/test_recorder.py +++ b/frappe/tests/test_recorder.py @@ -109,7 +109,7 @@ class TestRecorder(FrappeTestCase): self.assertEqual(len(request["calls"]), len(queries)) - for query, call in zip(queries, request["calls"]): + for query, call in zip(queries, request["calls"], strict=False): self.assertEqual( call["query"], sqlparse.format( @@ -134,7 +134,7 @@ class TestRecorder(FrappeTestCase): requests = frappe.recorder.get() request = frappe.recorder.get(requests[0]["uuid"]) - for query, call in zip(queries, request["calls"]): + for query, call in zip(queries, request["calls"], strict=False): self.assertEqual(call["exact_copies"], query[1]) def test_error_page_rendering(self): diff --git a/frappe/tests/test_safe_exec.py b/frappe/tests/test_safe_exec.py index 2f70dc0e5c..e86669f153 100644 --- a/frappe/tests/test_safe_exec.py +++ b/frappe/tests/test_safe_exec.py @@ -93,7 +93,7 @@ class TestSafeExec(FrappeTestCase): def test_ensure_getattrable_globals(self): def check_safe(objects): for obj in objects: - if isinstance(obj, (types.ModuleType, types.CodeType, types.TracebackType, types.FrameType)): + if isinstance(obj, types.ModuleType | types.CodeType | types.TracebackType | types.FrameType): self.fail(f"{obj} wont work in safe exec.") elif isinstance(obj, dict): check_safe(obj.values()) diff --git a/frappe/tests/test_translate.py b/frappe/tests/test_translate.py index f83cfb15b0..613a8b5472 100644 --- a/frappe/tests/test_translate.py +++ b/frappe/tests/test_translate.py @@ -74,7 +74,7 @@ class TestTranslate(FrappeTestCase): msg=f"Mismatched output:\nExpected: {expected_output}\nFound: {data}", ) - for extracted, expected in zip(data, expected_output): + for extracted, expected in zip(data, expected_output, strict=False): ext_filename, ext_message, ext_context, ext_line = extracted exp_message, exp_context, exp_line = expected self.assertEqual(ext_filename, exp_filename) @@ -214,7 +214,7 @@ class TestTranslate(FrappeTestCase): output = extract_messages_from_python_code(code) self.assertEqual(len(expected_output), len(output)) - for expected, actual in zip(expected_output, output): + for expected, actual in zip(expected_output, output, strict=False): with self.subTest(): self.assertEqual(expected, actual) @@ -251,7 +251,7 @@ class TestTranslate(FrappeTestCase): output = extract_messages_from_javascript_code(code) self.assertEqual(len(expected_output), len(output)) - for expected, actual in zip(expected_output, output): + for expected, actual in zip(expected_output, output, strict=False): with self.subTest(): self.assertEqual(expected, actual) diff --git a/frappe/tests/test_twofactor.py b/frappe/tests/test_twofactor.py index ca462a9e34..5108df7f75 100644 --- a/frappe/tests/test_twofactor.py +++ b/frappe/tests/test_twofactor.py @@ -232,7 +232,7 @@ def toggle_2fa_all_role(state=None): """Enable or disable 2fa for 'all' role on the system.""" all_role = frappe.get_doc("Role", "All") state = state if state is not None else False - if type(state) != bool: + if not isinstance(state, bool): return all_role.two_factor_auth = cint(state) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index 482cc80e5a..bb21c8c633 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -46,7 +46,11 @@ from frappe.utils import ( validate_phone_number_with_country_code, validate_url, ) -from frappe.utils.change_log import check_release_on_github, get_remote_url, parse_github_url +from frappe.utils.change_log import ( + check_release_on_github, + get_remote_url, + parse_github_url, +) from frappe.utils.data import ( add_to_date, add_years, @@ -98,7 +102,8 @@ class TestFilters(FrappeTestCase): def test_multiple_dict(self): self.assertTrue( evaluate_filters( - {"doctype": "User", "status": "Open", "name": "Test 1"}, {"status": "Open", "name": "Test 1"} + {"doctype": "User", "status": "Open", "name": "Test 1"}, + {"status": "Open", "name": "Test 1"}, ) ) self.assertFalse( @@ -139,12 +144,14 @@ class TestFilters(FrappeTestCase): def test_lt_gt(self): self.assertTrue( evaluate_filters( - {"doctype": "User", "status": "Open", "age": 20}, {"status": "Open", "age": (">", 10)} + {"doctype": "User", "status": "Open", "age": 20}, + {"status": "Open", "age": (">", 10)}, ) ) self.assertFalse( evaluate_filters( - {"doctype": "User", "status": "Open", "age": 20}, {"status": "Open", "age": (">", 30)} + {"doctype": "User", "status": "Open", "age": 20}, + {"status": "Open", "age": (">", 30)}, ) ) @@ -152,12 +159,14 @@ class TestFilters(FrappeTestCase): # date fields self.assertTrue( evaluate_filters( - {"doctype": "User", "birth_date": "2023-02-28"}, [("User", "birth_date", ">", "01-04-2022")] + {"doctype": "User", "birth_date": "2023-02-28"}, + [("User", "birth_date", ">", "01-04-2022")], ) ) self.assertFalse( evaluate_filters( - {"doctype": "User", "birth_date": "2023-02-28"}, [("User", "birth_date", "<", "28-02-2023")] + {"doctype": "User", "birth_date": "2023-02-28"}, + [("User", "birth_date", "<", "28-02-2023")], ) ) @@ -176,7 +185,12 @@ class TestFilters(FrappeTestCase): ) def test_like_not_like(self): - doc = {"doctype": "User", "username": "test_abc", "prefix": "startswith", "suffix": "endswith"} + doc = { + "doctype": "User", + "username": "test_abc", + "prefix": "startswith", + "suffix": "endswith", + } test_cases = [ ([["username", "like", "test"]], True), @@ -371,7 +385,11 @@ class TestValidationUtils(FrappeTestCase): self.assertTrue(validate_url("ftp://frappe.cloud", valid_schemes=["https", "ftp"])) self.assertFalse(validate_url("bolo://frappe.io", valid_schemes=("http", "https", "ftp", "ftps"))) self.assertRaises( - frappe.ValidationError, validate_url, "gopher://frappe.io", valid_schemes="https", throw=True + frappe.ValidationError, + validate_url, + "gopher://frappe.io", + valid_schemes="https", + throw=True, ) def test_valid_email(self): @@ -391,7 +409,12 @@ class TestValidationUtils(FrappeTestCase): self.assertFalse(validate_email_address("test@example.com test2@example.com,undisclosed-recipient")) # Invalid with throw - self.assertRaises(frappe.InvalidEmailAddressError, validate_email_address, "someone.com", throw=True) + self.assertRaises( + frappe.InvalidEmailAddressError, + validate_email_address, + "someone.com", + throw=True, + ) self.assertEqual(validate_email_address("Some%20One@frappe.com"), "Some%20One@frappe.com") self.assertEqual( @@ -425,7 +448,8 @@ class TestImage(FrappeTestCase): def test_strip_exif_data(self): original_image = Image.open(frappe.get_app_path("frappe", "tests", "data", "exif_sample_image.jpg")) original_image_content = open( - frappe.get_app_path("frappe", "tests", "data", "exif_sample_image.jpg"), mode="rb" + frappe.get_app_path("frappe", "tests", "data", "exif_sample_image.jpg"), + mode="rb", ).read() new_image_content = strip_exif_data(original_image_content, "image/jpeg") @@ -522,19 +546,33 @@ class TestDateUtils(FrappeTestCase): # Monday as start of the week with patch.object(frappe.utils.data, "get_first_day_of_the_week", return_value="Monday"): self.assertEqual( - frappe.utils.get_first_day_of_week("2020-12-25"), frappe.utils.getdate("2020-12-21") + frappe.utils.get_first_day_of_week("2020-12-25"), + frappe.utils.getdate("2020-12-21"), ) self.assertEqual( - frappe.utils.get_first_day_of_week("2020-12-20"), frappe.utils.getdate("2020-12-14") + frappe.utils.get_first_day_of_week("2020-12-20"), + frappe.utils.getdate("2020-12-14"), ) # Sunday as start of the week - self.assertEqual(frappe.utils.get_first_day_of_week("2020-12-25"), frappe.utils.getdate("2020-12-20")) - self.assertEqual(frappe.utils.get_first_day_of_week("2020-12-21"), frappe.utils.getdate("2020-12-20")) + self.assertEqual( + frappe.utils.get_first_day_of_week("2020-12-25"), + frappe.utils.getdate("2020-12-20"), + ) + self.assertEqual( + frappe.utils.get_first_day_of_week("2020-12-21"), + frappe.utils.getdate("2020-12-20"), + ) def test_last_day_of_week(self): - self.assertEqual(frappe.utils.get_last_day_of_week("2020-12-24"), frappe.utils.getdate("2020-12-26")) - self.assertEqual(frappe.utils.get_last_day_of_week("2020-12-28"), frappe.utils.getdate("2021-01-02")) + self.assertEqual( + frappe.utils.get_last_day_of_week("2020-12-24"), + frappe.utils.getdate("2020-12-26"), + ) + self.assertEqual( + frappe.utils.get_last_day_of_week("2020-12-28"), + frappe.utils.getdate("2021-01-02"), + ) def test_is_last_day_of_the_month(self): self.assertEqual(frappe.utils.is_last_day_of_the_month("2020-12-24"), False) @@ -674,7 +712,14 @@ class TestResponse(FrappeTestCase): "time_types": [ date(year=2020, month=12, day=2), datetime( - year=2020, month=12, day=2, hour=23, minute=23, second=23, microsecond=23, tzinfo=pytz.utc + year=2020, + month=12, + day=2, + hour=23, + minute=23, + second=23, + microsecond=23, + tzinfo=pytz.utc, ), time(hour=23, minute=23, second=23, microsecond=23, tzinfo=pytz.utc), timedelta(days=10, hours=12, minutes=120, seconds=10), @@ -699,7 +744,7 @@ class TestResponse(FrappeTestCase): self.assertTrue(all([isinstance(x, str) for x in processed_object["time_types"]])) self.assertTrue(all([isinstance(x, float) for x in processed_object["float"]])) - self.assertTrue(all([isinstance(x, (list, str)) for x in processed_object["iter"]])) + self.assertTrue(all([isinstance(x, list | str) for x in processed_object["iter"]])) self.assertIsInstance(processed_object["string"], str) with self.assertRaises(TypeError): json.dumps(BAD_OBJECT, default=json_handler) @@ -711,13 +756,17 @@ class TestTimeDeltaUtils(FrappeTestCase): self.assertEqual(format_timedelta(timedelta(hours=10)), "10:00:00") self.assertEqual(format_timedelta(timedelta(hours=100)), "100:00:00") self.assertEqual(format_timedelta(timedelta(seconds=100, microseconds=129)), "0:01:40.000129") - self.assertEqual(format_timedelta(timedelta(seconds=100, microseconds=12212199129)), "3:25:12.199129") + self.assertEqual( + format_timedelta(timedelta(seconds=100, microseconds=12212199129)), + "3:25:12.199129", + ) def test_parse_timedelta(self): self.assertEqual(parse_timedelta("0:0:0"), timedelta(seconds=0)) self.assertEqual(parse_timedelta("10:0:0"), timedelta(hours=10)) self.assertEqual( - parse_timedelta("7 days, 0:32:18.192221"), timedelta(days=7, seconds=1938, microseconds=192221) + parse_timedelta("7 days, 0:32:18.192221"), + timedelta(days=7, seconds=1938, microseconds=192221), ) self.assertEqual(parse_timedelta("7 days, 0:32:18"), timedelta(days=7, seconds=1938)) @@ -982,7 +1031,7 @@ class TestMiscUtils(FrappeTestCase): class TestTypingValidations(FrappeTestCase): - ERR_REGEX = f"^Argument '.*' should be of type '.*' but got '.*' instead.$" + ERR_REGEX = "^Argument '.*' should be of type '.*' but got '.*' instead.$" def test_validate_whitelisted_api(self): from inspect import signature @@ -1009,9 +1058,9 @@ class TestTypingValidations(FrappeTestCase): class TestTBSanitization(FrappeTestCase): def test_traceback_sanitzation(self): try: - password = "42" - args = {"password": "42", "pwd": "42", "safe": "safe_value"} - args = frappe._dict({"password": "42", "pwd": "42", "safe": "safe_value"}) + password = "42" # noqa: F841 + args = {"password": "42", "pwd": "42", "safe": "safe_value"} # noqa: F841 + args = frappe._dict({"password": "42", "pwd": "42", "safe": "safe_value"}) # noqa: F841 raise Exception except Exception: traceback = frappe.get_traceback(with_context=True) @@ -1100,7 +1149,10 @@ class TestRounding(FrappeTestCase): self.assertEqual(flt(3.35, 1, rounding_method=rounding_method), 3.4) @change_settings("System Settings", {"rounding_method": "Commercial Rounding"}) - @given(st.decimals(min_value=-1e8, max_value=1e8), st.integers(min_value=-2, max_value=4)) + @given( + st.decimals(min_value=-1e8, max_value=1e8), + st.integers(min_value=-2, max_value=4), + ) def test_normal_rounding_property(self, number, precision): with localcontext() as ctx: ctx.rounding = ROUND_HALF_UP @@ -1165,7 +1217,10 @@ class TestRounding(FrappeTestCase): self.assertEqual(flt(-3.35, 1, rounding_method=rounding_method), -3.4) @change_settings("System Settings", {"rounding_method": "Banker's Rounding"}) - @given(st.decimals(min_value=-1e8, max_value=1e8), st.integers(min_value=-2, max_value=4)) + @given( + st.decimals(min_value=-1e8, max_value=1e8), + st.integers(min_value=-2, max_value=4), + ) def test_bankers_rounding_property(self, number, precision): self.assertEqual(Decimal(str(flt(float(number), precision))), round(number, precision)) @@ -1173,10 +1228,13 @@ class TestRounding(FrappeTestCase): self.assertEqual(frappe.get_system_settings("rounding_method"), "Banker's Rounding") -class TestTypingValidations(FrappeTestCase): +class TestArgumentTypingValidations(FrappeTestCase): def test_validate_argument_types(self): from frappe.core.doctype.doctype.doctype import DocType - from frappe.utils.typing_validations import FrappeTypeError, validate_argument_types + from frappe.utils.typing_validations import ( + FrappeTypeError, + validate_argument_types, + ) @validate_argument_types def test_simple_types(a: int, b: float, c: bool): diff --git a/frappe/tests/utils.py b/frappe/tests/utils.py index 9b667b016d..a1f0c29941 100644 --- a/frappe/tests/utils.py +++ b/frappe/tests/utils.py @@ -60,7 +60,7 @@ class FrappeTestCase(unittest.TestCase): if isinstance(value, list): actual_child_docs = actual.get(field) self.assertEqual(len(value), len(actual_child_docs), msg=f"{field} length should be same") - for exp_child, actual_child in zip(value, actual_child_docs): + for exp_child, actual_child in zip(value, actual_child_docs, strict=False): self.assertDocumentEqual(exp_child, actual_child) else: self._compare_field(value, actual.get(field), actual, field) @@ -73,7 +73,7 @@ class FrappeTestCase(unittest.TestCase): self.assertAlmostEqual( expected, actual, places=precision, msg=f"{field} should be same to {precision} digits" ) - elif isinstance(expected, (bool, int)): + elif isinstance(expected, bool | int): self.assertEqual(expected, cint(actual), msg=msg) elif isinstance(expected, datetime_like_types): self.assertEqual(str(expected), str(actual), msg=msg) diff --git a/frappe/translate.py b/frappe/translate.py index e5527883f7..8a476eb9b0 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -204,9 +204,7 @@ def get_translation_dict_from_file(path, lang, app, throw=False) -> dict[str, st elif len(item) in [2, 3]: translation_map[item[0]] = strip(item[1]) elif item: - msg = "Bad translation in '{app}' for language '{lang}': {values}".format( - app=app, lang=lang, values=cstr(item) - ) + msg = f"Bad translation in '{app}' for language '{lang}': {cstr(item)}" frappe.log_error(message=msg, title="Error in translation file") if throw: frappe.throw(msg, title="Error in translation file") @@ -545,7 +543,7 @@ def get_all_messages_from_js_files(app_name=None): messages = [] for app in [app_name] if app_name else frappe.get_installed_apps(_ensure_on_bench=True): if os.path.exists(frappe.get_app_path(app, "public")): - for basepath, folders, files in os.walk(frappe.get_app_path(app, "public")): + for basepath, folders, files in os.walk(frappe.get_app_path(app, "public")): # noqa: B007 if "frappe/public/js/lib" in basepath: continue @@ -761,6 +759,7 @@ def update_translations(lang, untranslated_file, translated_file, app="_ALL_APPS for key, value in zip( frappe.get_file_items(untranslated_file, ignore_empty_lines=False), frappe.get_file_items(translated_file, ignore_empty_lines=False), + strict=False, ): # undo hack in get_untranslated translation_dict[restore_newlines(key)] = restore_newlines(value) diff --git a/frappe/twofactor.py b/frappe/twofactor.py index ad422c0224..c9263aa336 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -219,7 +219,6 @@ def process_2fa_for_sms(user, token, otp_secret): def process_2fa_for_otp_app(user, otp_secret, otp_issuer): """Process OTP App method for 2fa.""" - totp_uri = pyotp.TOTP(otp_secret).provisioning_uri(user, issuer_name=otp_issuer) if get_default(user + "_otplogin"): otp_setup_completed = True else: diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index c7cd1daf30..a750f3ca78 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -233,7 +233,7 @@ def validate_url( # Handle scheme validation if isinstance(valid_schemes, str): is_valid = is_valid and (url.scheme == valid_schemes) - elif isinstance(valid_schemes, (list, tuple, set)): + elif isinstance(valid_schemes, list | tuple | set): is_valid = is_valid and (url.scheme in valid_schemes) if not is_valid and throw: @@ -386,7 +386,7 @@ def set_default(key, val): def remove_blanks(d: dict) -> dict: """Return d with empty ('' or None) values stripped. Mutates inplace.""" for k, v in tuple(d.items()): - if v == "" or v == None: + if not v: del d[k] return d @@ -657,7 +657,7 @@ def is_markdown(text): def is_a_property(x) -> bool: """Get properties (@property, @cached_property) in a controller class""" - return isinstance(x, (property, functools.cached_property)) + return isinstance(x, property | functools.cached_property) def get_sites(sites_path=None): @@ -904,7 +904,7 @@ def get_safe_filters(filters): try: filters = json.loads(filters) - if isinstance(filters, (int, float)): + if isinstance(filters, int | float): filters = frappe.as_unicode(filters) except (TypeError, ValueError): diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index 8e4313d10a..ce819195ec 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -350,9 +350,7 @@ def get_worker_name(queue): if queue: # hostname.pid is the default worker name - name = "{uuid}.{hostname}.{pid}.{queue}".format( - uuid=uuid4().hex, hostname=socket.gethostname(), pid=os.getpid(), queue=queue - ) + name = f"{uuid4().hex}.{socket.gethostname()}.{os.getpid()}.{queue}" return name diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index 4f8ce825f4..b9fa0d1022 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -462,7 +462,7 @@ class BackupGenerator: db_backup_url = get_url(os.path.join("backups", os.path.basename(self.backup_path_db))) files_backup_url = get_url(os.path.join("backups", os.path.basename(self.backup_path_files))) - msg = """Hello, + msg = f"""Hello, Your backups are ready to be downloaded. @@ -470,10 +470,7 @@ Your backups are ready to be downloaded. 2. [Click here to download the files backup]({files_backup_url}) This link will be valid for 24 hours. A new backup will be available for -download only after 24 hours.""".format( - db_backup_url=db_backup_url, - files_backup_url=files_backup_url, - ) +download only after 24 hours.""" datetime_str = datetime.fromtimestamp(os.stat(self.backup_path_db).st_ctime) subject = datetime_str.strftime("%d/%m/%Y %H:%M:%S") + """ - Backup ready to be downloaded""" diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 812f84c3b2..d875a6afad 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -145,9 +145,7 @@ def _create_app_boilerplate(dest, hooks, no_git=False): with open(os.path.join(dest, hooks.app_name, "README.md"), "w") as f: f.write( frappe.as_unicode( - "## {}\n\n{}\n\n#### License\n\n{}".format( - hooks.app_title, hooks.app_description, hooks.app_license - ) + f"## {hooks.app_title}\n\n{hooks.app_description}\n\n#### License\n\n{hooks.app_license}" ) ) license_body = get_license_text(license_name=hooks.app_license) diff --git a/frappe/utils/change_log.py b/frappe/utils/change_log.py index a15d6afd95..4b4794c07a 100644 --- a/frappe/utils/change_log.py +++ b/frappe/utils/change_log.py @@ -118,9 +118,7 @@ def get_versions(): if versions[app]["branch"] != "master": branch_version = app_hooks.get("{}_version".format(versions[app]["branch"])) if branch_version: - versions[app]["branch_version"] = branch_version[0] + " ({})".format( - get_app_last_commit_ref(app) - ) + versions[app]["branch_version"] = branch_version[0] + f" ({get_app_last_commit_ref(app)})" try: versions[app]["version"] = frappe.get_attr(app + ".__version__") diff --git a/frappe/utils/csvutils.py b/frappe/utils/csvutils.py index fd39fdd482..74868ccecc 100644 --- a/frappe/utils/csvutils.py +++ b/frappe/utils/csvutils.py @@ -174,7 +174,7 @@ def import_doc(d, doctype, overwrite, row_idx, submit=False, ignore_links=False) def getlink(doctype, name): - return '%(name)s' % locals() + return '{name}'.format(**locals()) def get_csv_content_from_google_sheets(url): diff --git a/frappe/utils/dashboard.py b/frappe/utils/dashboard.py index d3fa6ac6fa..98c0b0c450 100644 --- a/frappe/utils/dashboard.py +++ b/frappe/utils/dashboard.py @@ -72,7 +72,6 @@ def generate_and_cache_results(args, function, cache_key, chart): def get_dashboards_with_link(docname, doctype): - dashboards = [] links = [] if doctype == "Dashboard Chart": @@ -111,4 +110,4 @@ def make_records(path, filters=None): if os.path.isdir(join(path, fname)): if fname == "__pycache__": continue - import_file_by_path("{path}/{fname}/{fname}.json".format(path=path, fname=fname)) + import_file_by_path(f"{path}/{fname}/{fname}.json") diff --git a/frappe/utils/data.py b/frappe/utils/data.py index a7eebe9342..3694c716d9 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -11,7 +11,7 @@ import time import typing from code import compile_command from enum import Enum -from typing import Any, Literal, Optional, TypeVar, Union +from typing import Any, Literal, Optional, TypeVar from urllib.parse import parse_qsl, quote, urlencode, urljoin, urlparse, urlunparse import pytz @@ -23,8 +23,8 @@ from dateutil.relativedelta import relativedelta import frappe from frappe.desk.utils import slug -DateTimeLikeObject = Union[str, datetime.date, datetime.datetime] -NumericType = Union[int, float] +DateTimeLikeObject = str | datetime.date | datetime.datetime +NumericType = int | float TimespanOptions = Literal[ "last week", "last month", @@ -142,10 +142,10 @@ def get_datetime( if datetime_str is None: return now_datetime() - if isinstance(datetime_str, (datetime.datetime, datetime.timedelta)): + if isinstance(datetime_str, datetime.datetime | datetime.timedelta): return datetime_str - elif isinstance(datetime_str, (list, tuple)): + elif isinstance(datetime_str, list | tuple): return datetime.datetime(datetime_str) elif isinstance(datetime_str, datetime.date): @@ -1316,7 +1316,7 @@ def encode(obj, encoding="utf-8"): def parse_val(v): """Convert to simple datatypes from SQL query results.""" - if isinstance(v, (datetime.date, datetime.datetime)): + if isinstance(v, datetime.date | datetime.datetime): v = str(v) elif isinstance(v, datetime.timedelta): v = ":".join(str(v).split(":")[:2]) @@ -1690,7 +1690,7 @@ def comma_sep(some_list: list | tuple, pattern: str, add_quotes=True) -> str: e.g. if `some_list` is ['a', 'b', 'c'] and `pattern` is '{0} or {1}', the output will be 'a, b or c' """ - if isinstance(some_list, (list, tuple)): + if isinstance(some_list, list | tuple): # list(some_list) is done to preserve the existing list some_list = [str(s) for s in list(some_list)] if not some_list: @@ -1709,7 +1709,7 @@ def new_line_sep(some_list: list | tuple) -> str: e.g. ['', 'Paid', 'Unpaid'] -> '\n Paid\n Unpaid' """ - if isinstance(some_list, (list, tuple)): + if isinstance(some_list, list | tuple): # list(some_list) is done to preserve the existing list some_list = [str(s) for s in list(some_list)] if not some_list: @@ -1947,7 +1947,7 @@ def evaluate_filters(doc, filters: dict | list | tuple): if not compare(doc.get(f.fieldname), f.operator, f.value, f.fieldtype): return False - elif isinstance(filters, (list, tuple)): + elif isinstance(filters, list | tuple): for d in filters: f = get_filter(None, d) if not compare(doc.get(f.fieldname), f.operator, f.value, f.fieldtype): @@ -1984,7 +1984,7 @@ def get_filter(doctype: str, f: dict | list | tuple, filters_config=None) -> "fr key, value = next(iter(f.items())) f = make_filter_tuple(doctype, key, value) - if not isinstance(f, (list, tuple)): + if not isinstance(f, list | tuple): frappe.throw(frappe._("Filter must be a tuple or list (in a list)")) if len(f) == 3: @@ -2051,7 +2051,7 @@ def get_filter(doctype: str, f: dict | list | tuple, filters_config=None) -> "fr def make_filter_tuple(doctype, key, value): """return a filter tuple like [doctype, key, operator, value]""" - if isinstance(value, (list, tuple)): + if isinstance(value, list | tuple): return [doctype, key, value[0], value[1]] else: return [doctype, key, "=", value] diff --git a/frappe/utils/dateutils.py b/frappe/utils/dateutils.py index 73880d2907..0792113dcd 100644 --- a/frappe/utils/dateutils.py +++ b/frappe/utils/dateutils.py @@ -66,9 +66,8 @@ def parse_date(date): if not parsed_date: raise Exception( - """Cannot understand date - '%s'. - Try formatting it like your default format - '%s'""" - % (date, get_user_date_format()) + f"""Cannot understand date - '{date}'. + Try formatting it like your default format - '{get_user_date_format()}'""" ) return parsed_date diff --git a/frappe/utils/global_search.py b/frappe/utils/global_search.py index cef7ab2188..cf80557a56 100644 --- a/frappe/utils/global_search.py +++ b/frappe/utils/global_search.py @@ -511,7 +511,7 @@ def search(text, start=0, limit=20, doctype=""): # sort results based on allowed_doctype's priority for doctype in allowed_doctypes: - for index, r in enumerate(results): + for r in results: if r.doctype == doctype and r.rank > 0.0: try: meta = frappe.get_meta(r.doctype) diff --git a/frappe/utils/image.py b/frappe/utils/image.py index 1d16ee690a..ecffe21fed 100644 --- a/frappe/utils/image.py +++ b/frappe/utils/image.py @@ -10,7 +10,7 @@ import frappe def resize_images(path, maxdim=700): size = (maxdim, maxdim) - for basepath, folders, files in os.walk(path): + for basepath, folders, files in os.walk(path): # noqa: B007 for fname in files: extn = fname.rsplit(".", 1)[1] if extn in ("jpg", "jpeg", "png", "gif"): diff --git a/frappe/utils/jinja_globals.py b/frappe/utils/jinja_globals.py index e1efb6d1dd..848f41c527 100644 --- a/frappe/utils/jinja_globals.py +++ b/frappe/utils/jinja_globals.py @@ -11,7 +11,7 @@ def resolve_class(*classes): if classes is False: return "" - if isinstance(classes, (list, tuple)): + if isinstance(classes, list | tuple): return " ".join(resolve_class(c) for c in classes).strip() if isinstance(classes, dict): diff --git a/frappe/utils/make_random.py b/frappe/utils/make_random.py index 381f2266a3..4167eedf51 100644 --- a/frappe/utils/make_random.py +++ b/frappe/utils/make_random.py @@ -18,7 +18,7 @@ def add_random_children(doc: "Document", fieldname: str, rows, randomize: dict, if rows > 1: nrows = random.randrange(1, rows) - for i in range(nrows): + for _ in range(nrows): d = {} for key, val in randomize.items(): if isinstance(val[0], str): @@ -41,12 +41,10 @@ def get_random(doctype: str, filters: dict = None, doc: bool = False): out = frappe.db.multisql( { - "mariadb": """select name from `tab%s` %s - order by RAND() limit 1 offset 0""" - % (doctype, condition), - "postgres": """select name from `tab%s` %s - order by RANDOM() limit 1 offset 0""" - % (doctype, condition), + "mariadb": f"""select name from `tab{doctype}` {condition} + order by RAND() limit 1 offset 0""", + "postgres": f"""select name from `tab{doctype}` {condition} + order by RANDOM() limit 1 offset 0""", } ) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index bfa2577871..29c76d7615 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -65,7 +65,7 @@ def download_multi_pdf(doctype, name, format=None, no_letterhead=False, letterhe result = json.loads(name) # Concatenating pdf files - for i, ss in enumerate(result): + for ss in result: pdf_writer = frappe.get_print( doctype, ss, diff --git a/frappe/utils/redis_wrapper.py b/frappe/utils/redis_wrapper.py index bd82db4738..8128341edb 100644 --- a/frappe/utils/redis_wrapper.py +++ b/frappe/utils/redis_wrapper.py @@ -134,7 +134,7 @@ class RedisWrapper(redis.Redis): if not keys: return - if not isinstance(keys, (list, tuple)): + if not isinstance(keys, list | tuple): keys = (keys,) if make_keys: diff --git a/frappe/utils/response.py b/frappe/utils/response.py index 8aa63ba990..87ca56951b 100644 --- a/frappe/utils/response.py +++ b/frappe/utils/response.py @@ -205,7 +205,7 @@ def json_handler(obj): from collections.abc import Iterable from re import Match - if isinstance(obj, (datetime.date, datetime.datetime, datetime.time)): + if isinstance(obj, datetime.date | datetime.datetime | datetime.time): return str(obj) elif isinstance(obj, datetime.timedelta): diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py index e68259d893..a6494cf853 100644 --- a/frappe/utils/safe_exec.py +++ b/frappe/utils/safe_exec.py @@ -498,7 +498,7 @@ def _validate_attribute_read(object, name): if isinstance(name, str) and (name in UNSAFE_ATTRIBUTES): raise SyntaxError(f"{name} is an unsafe attribute") - if isinstance(object, (types.ModuleType, types.CodeType, types.TracebackType, types.FrameType)): + if isinstance(object, types.ModuleType | types.CodeType | types.TracebackType | types.FrameType): raise SyntaxError(f"Reading {object} attributes is not allowed") if name.startswith("_"): @@ -509,16 +509,14 @@ def _write(obj): # guard function for RestrictedPython if isinstance( obj, - ( - types.ModuleType, - types.CodeType, - types.TracebackType, - types.FrameType, - type, - types.FunctionType, # covers lambda - types.MethodType, - types.BuiltinFunctionType, # covers methods - ), + types.ModuleType + | types.CodeType + | types.TracebackType + | types.FrameType + | type + | types.FunctionType + | types.MethodType + | types.BuiltinFunctionType, ): raise SyntaxError(f"Not allowed to write to object {obj} of type {type(obj)}") return obj diff --git a/frappe/utils/typing_validations.py b/frappe/utils/typing_validations.py index ce521e996c..6786a7aff9 100644 --- a/frappe/utils/typing_validations.py +++ b/frappe/utils/typing_validations.py @@ -1,7 +1,7 @@ from collections.abc import Callable from functools import lru_cache, wraps from inspect import _empty, isclass, signature -from types import EllipsisType, NoneType +from types import EllipsisType from typing import ForwardRef, TypeVar, Union from pydantic import ConfigDict @@ -93,11 +93,11 @@ def transform_parameter_types(func: Callable, args: tuple, kwargs: dict): elif kwargs: arg_values = args or func.__defaults__ or [] - prepared_args = dict(zip(arg_names, arg_values)) + prepared_args = dict(zip(arg_names, arg_values, strict=False)) prepared_args.update(kwargs) else: - prepared_args = dict(zip(arg_names, args)) + prepared_args = dict(zip(arg_names, args, strict=False)) # check if type hints dont match the default values func_signature = signature(func) @@ -111,9 +111,9 @@ def transform_parameter_types(func: Callable, args: tuple, kwargs: dict): current_arg_value = prepared_args[current_arg] # if the type is a ForwardRef or str, ignore it - if isinstance(current_arg_type, (ForwardRef, str)): + if isinstance(current_arg_type, ForwardRef | str): continue - elif any(isinstance(x, (ForwardRef, str)) for x in getattr(current_arg_type, "__args__", [])): + elif any(isinstance(x, ForwardRef | str) for x in getattr(current_arg_type, "__args__", [])): continue # allow slack for Frappe types @@ -127,12 +127,12 @@ def transform_parameter_types(func: Callable, args: tuple, kwargs: dict): if isinstance(current_arg_type, tuple): if type(param_def.default) not in current_arg_type: current_arg_type += (type(param_def.default),) - current_arg_type = Union[current_arg_type] + current_arg_type = Union[current_arg_type] # noqa: UP007 elif param_def.default != current_arg_type: - current_arg_type = Union[current_arg_type, type(param_def.default)] + current_arg_type = Union[current_arg_type, type(param_def.default)] # noqa: UP007 elif isinstance(current_arg_type, tuple): - current_arg_type = Union[current_arg_type] + current_arg_type = Union[current_arg_type] # noqa: UP007 # validate the type set using pydantic - raise a TypeError if Validation is raised or Ellipsis is returned try: diff --git a/frappe/website/doctype/blog_post/test_blog_post.py b/frappe/website/doctype/blog_post/test_blog_post.py index b11f2f3497..1a8cf3e87d 100644 --- a/frappe/website/doctype/blog_post/test_blog_post.py +++ b/frappe/website/doctype/blog_post/test_blog_post.py @@ -84,7 +84,7 @@ class TestBlogPost(FrappeTestCase): # Create some Blog Posts for a Blog Category category_title, blogs, BLOG_COUNT = "List Category", [], 4 - for index in range(BLOG_COUNT): + for _ in range(BLOG_COUNT): blog = make_test_blog(category_title) blogs.append(blog) diff --git a/frappe/website/doctype/website_settings/website_settings.py b/frappe/website/doctype/website_settings/website_settings.py index 70c5b04295..567c56f1d6 100644 --- a/frappe/website/doctype/website_settings/website_settings.py +++ b/frappe/website/doctype/website_settings/website_settings.py @@ -236,7 +236,7 @@ def get_website_settings(context=None): for key in via_hooks: context[key] = via_hooks[key] if key not in ("top_bar_items", "footer_items", "post_login") and isinstance( - context[key], (list, tuple) + context[key], list | tuple ): context[key] = context[key][-1] diff --git a/frappe/website/page_renderers/template_page.py b/frappe/website/page_renderers/template_page.py index 84a9d26081..d3b2b07506 100644 --- a/frappe/website/page_renderers/template_page.py +++ b/frappe/website/page_renderers/template_page.py @@ -201,8 +201,8 @@ class TemplatePage(BaseTemplatePage): and "{% extends" not in self.source and "" not in self.source ): - self.source = """{{% extends "{0}" %}} - {{% block page_content %}}{1}{{% endblock %}}""".format(context.base_template, self.source) + self.source = f"""{{% extends "{context.base_template}" %}} + {{% block page_content %}}{self.source}{{% endblock %}}""" self.set_properties_via_comments() diff --git a/frappe/website/report/website_analytics/website_analytics.py b/frappe/website/report/website_analytics/website_analytics.py index a395e5e582..916852f836 100644 --- a/frappe/website/report/website_analytics/website_analytics.py +++ b/frappe/website/report/website_analytics/website_analytics.py @@ -80,16 +80,16 @@ class WebsiteAnalytics: elif filters_range == "Monthly": date_format = "%Y-%m-01" - query = """ + query = f""" SELECT - DATE_FORMAT({0}, %s) as date, + DATE_FORMAT({field}, %s) as date, COUNT(*) as count, COUNT(CASE WHEN is_unique = 1 THEN 1 END) as unique_count FROM `tabWeb Page View` WHERE creation BETWEEN %s AND %s - GROUP BY DATE_FORMAT({0}, %s) + GROUP BY DATE_FORMAT({field}, %s) ORDER BY creation - """.format(field) + """ values = (date_format, self.filters.from_date, self.filters.to_date, date_format) @@ -106,16 +106,16 @@ class WebsiteAnalytics: elif filters_range == "Monthly": granularity = "day" - query = """ + query = f""" SELECT - DATE_TRUNC(%s, {0}) as date, + DATE_TRUNC(%s, {field}) as date, COUNT(*) as count, COUNT(CASE WHEN CAST(is_unique as Integer) = 1 THEN 1 END) as unique_count FROM "tabWeb Page View" - WHERE coalesce("tabWeb Page View".{0}, '0001-01-01') BETWEEN %s AND %s - GROUP BY date_trunc(%s, {0}) + WHERE coalesce("tabWeb Page View".{field}, '0001-01-01') BETWEEN %s AND %s + GROUP BY date_trunc(%s, {field}) ORDER BY date - """.format(field) + """ values = (granularity, self.filters.from_date, self.filters.to_date, granularity) diff --git a/frappe/website/router.py b/frappe/website/router.py index 332be38cda..41c8706331 100644 --- a/frappe/website/router.py +++ b/frappe/website/router.py @@ -109,7 +109,7 @@ def get_pages_from_path(start, app, app_path): pages = {} start_path = os.path.join(app_path, start) if os.path.exists(start_path): - for basepath, folders, files in os.walk(start_path): + for basepath, folders, files in os.walk(start_path): # noqa: B007 # add missing __init__.py if "__init__.py" not in files and frappe.conf.get("developer_mode"): open(os.path.join(basepath, "__init__.py"), "a").close() diff --git a/frappe/workflow/doctype/workflow/workflow.py b/frappe/workflow/doctype/workflow/workflow.py index 04f1a9ceca..9593526832 100644 --- a/frappe/workflow/doctype/workflow/workflow.py +++ b/frappe/workflow/doctype/workflow/workflow.py @@ -71,12 +71,12 @@ class Workflow(Document): for d in states: if d.doc_status not in docstatus_map: frappe.db.sql( - """ - UPDATE `tab{doctype}` - SET `{field}` = %s - WHERE ifnull(`{field}`, '') = '' + f""" + UPDATE `tab{self.document_type}` + SET `{self.workflow_state_field}` = %s + WHERE ifnull(`{self.workflow_state_field}`, '') = '' AND `docstatus` = %s - """.format(doctype=self.document_type, field=self.workflow_state_field), + """, (d.state, d.doc_status), ) diff --git a/frappe/workflow/doctype/workflow_action/workflow_action.py b/frappe/workflow/doctype/workflow_action/workflow_action.py index 1826a338f3..c4180c47ba 100644 --- a/frappe/workflow/doctype/workflow_action/workflow_action.py +++ b/frappe/workflow/doctype/workflow_action/workflow_action.py @@ -74,10 +74,10 @@ def get_permission_query_conditions(user): .where(WorkflowActionPermittedRole.role.isin(roles)) ).get_sql() - return """(`tabWorkflow Action`.`name` in ({permitted_workflow_actions}) - or `tabWorkflow Action`.`user`={user}) + return f"""(`tabWorkflow Action`.`name` in ({permitted_workflow_actions}) + or `tabWorkflow Action`.`user`={frappe.db.escape(user)}) and `tabWorkflow Action`.`status`='Open' - """.format(permitted_workflow_actions=permitted_workflow_actions, user=frappe.db.escape(user)) + """ def has_permission(doc, user): diff --git a/frappe/www/list.py b/frappe/www/list.py index aaf20f8a05..4682302214 100644 --- a/frappe/www/list.py +++ b/frappe/www/list.py @@ -130,9 +130,7 @@ def set_route(context): elif context.doc and getattr(context.doc, "route", None): context.route = context.doc.route else: - context.route = "{}/{}".format( - context.pathname or quoted(context.doc.doctype), quoted(context.doc.name) - ) + context.route = f"{context.pathname or quoted(context.doc.doctype)}/{quoted(context.doc.name)}" def prepare_filters(doctype, controller, kwargs): @@ -155,7 +153,7 @@ def prepare_filters(doctype, controller, kwargs): filters[key] = val # filter the filters to include valid fields only - for fieldname, val in list(filters.items()): + for fieldname in list(filters.keys()): if not meta.has_field(fieldname): del filters[fieldname] diff --git a/frappe/www/printview.py b/frappe/www/printview.py index e17829de10..bc512fd111 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -470,7 +470,7 @@ def make_layout(doc: "Document", meta: "Meta", format_data=None) -> list: if df.fieldtype == "Section Break" or page == []: if len(page) > 1: - if page[-1]["has_data"] == False: + if not page[-1]["has_data"]: # truncate last section if empty del page[-1]