diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a49668a5f4..c3ad43c5be 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -22,3 +22,6 @@ b2fc959307c7c79f5584625569d5aed04133ba13 # Format codebase and sort imports c0c5b2ebdddbe8898ce2d5e5365f4931ff73b6bf + +# update python code to use 3.10 supported features +81b37cb7d2160866afa2496873656afe53f0c145 diff --git a/.github/helper/install.sh b/.github/helper/install.sh index 0160696cae..d038be1b23 100644 --- a/.github/helper/install.sh +++ b/.github/helper/install.sh @@ -17,21 +17,23 @@ if [ "$TYPE" == "server" ]; then fi if [ "$DB" == "mariadb" ];then - sudo apt install mariadb-client-10.3 - mysql --host 127.0.0.1 --port 3306 -u root -e "SET GLOBAL character_set_server = 'utf8mb4'"; - mysql --host 127.0.0.1 --port 3306 -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"; + curl -LsS -O https://downloads.mariadb.com/MariaDB/mariadb_repo_setup + sudo bash mariadb_repo_setup --mariadb-server-version=10.6 + sudo apt install mariadb-client - mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE DATABASE test_frappe_consumer"; - mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE USER 'test_frappe_consumer'@'localhost' IDENTIFIED BY 'test_frappe_consumer'"; - mysql --host 127.0.0.1 --port 3306 -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe_consumer\`.* TO 'test_frappe_consumer'@'localhost'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL character_set_server = 'utf8mb4'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"; - mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE DATABASE test_frappe_producer"; - mysql --host 127.0.0.1 --port 3306 -u root -e "CREATE USER 'test_frappe_producer'@'localhost' IDENTIFIED BY 'test_frappe_producer'"; - mysql --host 127.0.0.1 --port 3306 -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe_producer\`.* TO 'test_frappe_producer'@'localhost'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_consumer"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_consumer'@'localhost' IDENTIFIED BY 'test_frappe_consumer'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_consumer\`.* TO 'test_frappe_consumer'@'localhost'"; - mysql --host 127.0.0.1 --port 3306 -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'"; - mysql --host 127.0.0.1 --port 3306 -u root -e "FLUSH PRIVILEGES"; - fi + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_producer"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_producer'@'localhost' IDENTIFIED BY 'test_frappe_producer'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_producer\`.* TO 'test_frappe_producer'@'localhost'"; + + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "FLUSH PRIVILEGES"; + fi if [ "$DB" == "postgres" ];then echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_consumer" -U postgres; diff --git a/.github/helper/roulette.py b/.github/helper/roulette.py index ad2fd829dd..c240443e9a 100644 --- a/.github/helper/roulette.py +++ b/.github/helper/roulette.py @@ -9,7 +9,7 @@ from functools import lru_cache @lru_cache(maxsize=None) -def fetch_pr_data(pr_number, repo, endpoint): +def fetch_pr_data(pr_number, repo, endpoint=""): api_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}" if endpoint: @@ -37,7 +37,7 @@ def has_run_ui_tests_label(pr_number, repo="frappe/frappe"): return has_label(pr_number, "Run UI Tests", repo) def has_label(pr_number, label, repo="frappe/frappe"): - return any([label["name"] for label in fetch_pr_data(pr_number, repo, "")["labels"] if label["name"] == label]) + return any([fetched_label["name"] for fetched_label in fetch_pr_data(pr_number, repo)["labels"] if fetched_label["name"] == label]) def is_py(file): return file.endswith("py") @@ -49,7 +49,7 @@ def is_frontend_code(file): return file.lower().endswith((".css", ".scss", ".less", ".sass", ".styl", ".js", ".ts", ".vue")) def is_docs(file): - regex = re.compile(r'\.(md|png|jpg|jpeg|csv)$|^.github|LICENSE') + regex = re.compile(r'\.(md|png|jpg|jpeg|csv|svg)$|^.github|LICENSE') return bool(regex.search(file)) diff --git a/.github/workflows/patch-mariadb-tests.yml b/.github/workflows/patch-mariadb-tests.yml index 5194444d49..cb6c50fb9e 100644 --- a/.github/workflows/patch-mariadb-tests.yml +++ b/.github/workflows/patch-mariadb-tests.yml @@ -18,10 +18,10 @@ jobs: name: Patch Test services: - mysql: - image: mariadb:10.3 + mariadb: + image: mariadb:10.6 env: - MYSQL_ALLOW_EMPTY_PASSWORD: YES + MARIADB_ROOT_PASSWORD: travis ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 @@ -39,9 +39,9 @@ jobs: fi - name: Setup Python - uses: "gabrielfalcao/pyenv-action@v9" + uses: "gabrielfalcao/pyenv-action@v10" with: - versions: 3.10:latest, 3.7:latest, 2.7:latest + versions: 3.10:latest, 3.7:latest - name: Setup Node uses: actions/setup-node@v3 @@ -123,14 +123,10 @@ jobs: cd apps/frappe/ git remote set-url upstream https://github.com/frappe/frappe.git + pyenv global $(pyenv versions | grep '3.7') for version in $(seq 12 13) do echo "Updating to v$version" - if [ $version == 12 ]; then - pyenv global $(pyenv versions | grep '2.7') - elif [ $version == 13 ]; then - pyenv global $(pyenv versions | grep '3.7') - fi branch_name="version-$version-hotfix" git fetch --depth 1 upstream $branch_name:$branch_name git checkout -q -f $branch_name diff --git a/.github/workflows/server-mariadb-tests.yml b/.github/workflows/server-mariadb-tests.yml index 028ef30746..e7349c711d 100644 --- a/.github/workflows/server-mariadb-tests.yml +++ b/.github/workflows/server-mariadb-tests.yml @@ -27,10 +27,10 @@ jobs: name: Python Unit Tests (MariaDB) services: - mysql: - image: mariadb:10.3 + mariadb: + image: mariadb:10.6 env: - MYSQL_ALLOW_EMPTY_PASSWORD: YES + MARIADB_ROOT_PASSWORD: travis ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 65debe989c..cd2a9fa40a 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -26,10 +26,10 @@ jobs: name: UI Tests (Cypress) services: - mysql: - image: mariadb:10.3 + mariadb: + image: mariadb:10.6 env: - MYSQL_ALLOW_EMPTY_PASSWORD: YES + MARIADB_ROOT_PASSWORD: travis ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 diff --git a/.gitignore b/.gitignore index 7e3d178630..a134417a5c 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,6 @@ dist/ downloads/ eggs/ .eggs/ -lib/ lib64/ parts/ sdist/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e8a44f0d1e..b231221517 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ fail_fast: false repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.3.0 hooks: - id: trailing-whitespace files: "frappe.*" @@ -15,6 +15,16 @@ repos: args: ['--branch', 'develop'] - id: check-merge-conflict - id: check-ast + - id: check-json + - id: check-toml + - id: check-yaml + - id: debug-statements + + - repo: https://github.com/asottile/pyupgrade + rev: v2.34.0 + hooks: + - id: pyupgrade + args: ['--py310-plus'] - repo: https://github.com/adityahase/black rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119 @@ -31,9 +41,7 @@ repos: rev: 3.9.2 hooks: - id: flake8 - additional_dependencies: [ - 'flake8-bugbear', - ] + additional_dependencies: ['flake8-bugbear',] args: ['--config', '.github/helper/flake8.conf'] ci: diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index c11c0ab6a3..0000000000 --- a/.pylintrc +++ /dev/null @@ -1,2 +0,0 @@ -disable=access-member-before-definition -disable=no-member \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 44a7d2fd59..0000000000 --- a/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -BASEDIR := $(realpath .) - -clean: - find $(BASEDIR) | grep -E "__pycache__|\.pyc" | xargs rm -rf \ No newline at end of file diff --git a/attributions.md b/attributions.md index b7c72912e4..43c6b14912 100644 --- a/attributions.md +++ b/attributions.md @@ -1,50 +1,32 @@ -## Frappe framework includes these public works +## 3rd-Party Software Report -### Javascript / CSS +The following 3rd-party software packages may be used by or distributed with . -- Bootstrap: MIT License, (c) Twitter Inc, https://getbootstrap.com -- JQuery: MIT License, (c) JQuery Foundation, http://jquery.org/license -- JQuery UI: MIT License / GPL 2, (c) JQuery Foundation, https://jqueryui.com/about -- JQuery UI Bootstrap Theme: MIT / GPL 2, (c) Addy Osmani, http://addyosmani.github.com/jquery-ui-bootstrap -- QUnit: MIT License, (c) JQuery Foundation, http://jquery.org/license -- jquery.event.drag, MIT License, (c) 2010 Three Dub Media - http://threedubmedia.com -- JQuery Cookie Plugin, MIT / GPL 2, (c) 2011, Klaus Hartl -- JQuery Time Picker, MIT License, (c) 2013 Trent Richardson, http://trentrichardson.com/examples/timepicker -- JQuery Hotkeys Plugin, MIT License, (c) 2010, John Resig -- prettydate.js, MIT License, (c) 2011, John Resig -- JQuery Resize Event, MIT License, (c) 2010 "Cowboy" Ben Alman -- excanvas.js, Apache License Version 2.0, (c) 2006 Google Inc -- showdown.js - Javascript Markdown, BSD-style Open Source License, (c) 2007 John Fraser -- Beautify HTML - MIT License, (c) 2007-2013 Einar Lielmanis and contributors. -- JQuery Gantt - MIT License, http://taitems.github.com/jQuery.Gantt/ -- SlickGrid - MIT License, https://github.com/mleibman/SlickGrid -- MomentJS - MIT License, https://github.com/moment/moment -- JSColor - LGPL, (c) Jan Odvarko, http://jscolor.com -- FullCalendar - MIT License, (c) 2013 Adam Shaw, http://fullcalendar.io/license/ -- Sortable - MIT License (c) 2013-2015 Lebedev Konstantin http://rubaxa.github.io/Sortable/ - -### Python - -- minify.js - MIT License, (c) 2002 Douglas Crockford +- Bootstrap: MIT License, (c) Twitter Inc, +- JQuery: MIT License, (c) JQuery Foundation, +- FullCalendar - MIT License, (c) 2013 Adam Shaw, +- JSignature - MIT License, (c) 2012 Willow Systems Corp , (c) 2010 Brinley Ang +- PhotoSwipe - MIT License, (c) 2014-2015 Dmitry Semenov, +- Leaflet - (c) 2010-2016, Vladimir Agafonkin, (c) 2010-2011, CloudMade +- Leaflet.Locate - (c) 2016 Dominik Moritz +- Leaflet.draw - (c) 2012-2017, Jacob Toye, Jon West, Smartrak +- Leaflet.EasyButton - MIT License, (C) 2014 Daniel Montague +- Fluxify - GNU GENERAL PUBLIC LICENSE Version 2 (C) 1989 - 1991 Free Software Foundation, Inc., ### Icon Fonts -- Font Awesome - http://fontawesome.io/ - - Font License: SIL OFL 1.1 (http://scripts.sil.org/OFL) - - Code License: MIT (http://choosealicense.com/licenses/mit/) -- Octicons (c) GitHub Inc, https://octicons.github.com/ - - Font License: SIL OFL 1.1 (http://scripts.sil.org/OFL) - - Code License: MIT (http://choosealicense.com/licenses/mit/) -- Ionicons - MIT License, http://ionicons.com/ +- Font Awesome - + - Font License: SIL OFL 1.1 () + - Code License: MIT () +- Octicons (c) GitHub Inc, + - Font License: SIL OFL 1.1 () + - Code License: MIT () +- Inter - SIL Open Font License, 1.1 (c) 2020 Rasmus Andersson () ### IP Address Database -- GeoIP: (c) 2014 MaxMind, http://dev.maxmind.com/geoip/geoip2/downloadable/ - -### Wallpaper - -- Version 5 Wallpaper: http://magdeleine.co/photo-nick-west-n-139/ (Public Domain) +- GeoIP: (c) 2014 MaxMind, --- -Last updated: 1st Jan 2015 +Last updated: 4th July 2022 diff --git a/esbuild/sass_options.js b/esbuild/sass_options.js index fcc7e04ccd..0c1189e90c 100644 --- a/esbuild/sass_options.js +++ b/esbuild/sass_options.js @@ -12,6 +12,7 @@ let app_paths = app_list module.exports = { includePaths: [node_modules_path, ...app_paths], + quietDeps: true, importer: function(url) { if (url.startsWith("~")) { // strip ~ so that it can resolve from node_modules diff --git a/frappe/__init__.py b/frappe/__init__.py index c19e7a22cf..87b09d72a9 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -17,7 +17,7 @@ import json import os import re import warnings -from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, overload import click from werkzeug.local import Local, release_local @@ -79,7 +79,7 @@ class _dict(dict): return _dict(self) -def _(msg, lang=None, context=None) -> str: +def _(msg: str, lang: str | None = None, context: str | None = None) -> str: """Returns translated string in current lang, if exists. Usage: _('Change') @@ -104,7 +104,7 @@ def _(msg, lang=None, context=None) -> str: translated_string = "" if context: - string_key = "{msg}:{context}".format(msg=msg, context=context) + string_key = f"{msg}:{context}" translated_string = get_full_dict(lang).get(string_key) if not translated_string: @@ -114,7 +114,7 @@ def _(msg, lang=None, context=None) -> str: return translated_string or non_translated_string -def as_unicode(text, encoding="utf-8"): +def as_unicode(text: str, encoding: str = "utf-8") -> str: """Convert to unicode if required""" if isinstance(text, str): return text @@ -126,7 +126,7 @@ def as_unicode(text, encoding="utf-8"): return str(text) -def get_lang_dict(fortype, name=None): +def get_lang_dict(fortype: str, name: str | None = None) -> dict[str, str]: """Returns the translated language dict for the given type and name. :param fortype: must be one of `doctype`, `page`, `report`, `include`, `jsfile`, `boot` @@ -136,11 +136,11 @@ def get_lang_dict(fortype, name=None): return get_dict(fortype, name) -def set_user_lang(user, user_language=None): +def set_user_lang(user: str, user_language: str | None = None) -> None: """Guess and set user language for the session. `frappe.local.lang`""" from frappe.translate import get_user_lang - local.lang = get_user_lang(user) + local.lang = get_user_lang(user) or user_language # local-globals @@ -166,24 +166,22 @@ lang = local("lang") if TYPE_CHECKING: from frappe.database.mariadb.database import MariaDBDatabase from frappe.database.postgres.database import PostgresDatabase + from frappe.model.document import Document from frappe.query_builder.builder import MariaDB, Postgres from frappe.utils.redis_wrapper import RedisWrapper - db: Union[MariaDBDatabase, PostgresDatabase] - qb: Union[MariaDB, Postgres] + db: MariaDBDatabase | PostgresDatabase + qb: MariaDB | Postgres # end: static analysis hack -def init(site, sites_path=None, new_site=False): +def init(site: str, sites_path: str = ".", new_site: bool = False) -> None: """Initialize frappe for the current site. Reset thread locals `frappe.local`""" if getattr(local, "initialised", None): return - if not sites_path: - sites_path = "." - local.error_log = [] local.message_log = [] local.debug_log = [] @@ -251,7 +249,9 @@ def init(site, sites_path=None, new_site=False): local.initialised = True -def connect(site=None, db_name=None, set_admin_as_user=True): +def connect( + site: str | None = None, db_name: str | None = None, set_admin_as_user: bool = True +) -> None: """Connect to site database instance. :param site: If site is given, calls `frappe.init`. @@ -288,7 +288,7 @@ def connect_replica(): local.db = local.replica_db -def get_site_config(sites_path=None, site_path=None): +def get_site_config(sites_path: str | None = None, site_path: str | None = None) -> dict[str, Any]: """Returns `site_config.json` combined with `sites/common_site_config.json`. `site_config` is a set of site wide settings like database name, password, email etc.""" config = {} @@ -311,15 +311,15 @@ def get_site_config(sites_path=None, site_path=None): try: config.update(get_file_json(site_config)) except Exception as error: - click.secho("{0}/site_config.json is invalid".format(local.site), fg="red") + click.secho(f"{local.site}/site_config.json is invalid", fg="red") print(error) elif local.site and not local.flags.new_site: - raise IncorrectSitePath("{0} does not exist".format(local.site)) + raise IncorrectSitePath(f"{local.site} does not exist") return _dict(config) -def get_conf(site=None): +def get_conf(site: str | None = None) -> dict[str, Any]: if hasattr(local, "conf"): return local.conf @@ -363,14 +363,14 @@ def cache() -> "RedisWrapper": return redis_server -def get_traceback(with_context=False): +def get_traceback(with_context: bool = False) -> str: """Returns error traceback.""" from frappe.utils import get_traceback return get_traceback(with_context=with_context) -def errprint(msg): +def errprint(msg: str) -> None: """Log error. This is sent back as `exc` in response. :param msg: Message.""" @@ -381,11 +381,11 @@ def errprint(msg): error_log.append({"exc": msg}) -def print_sql(enable=True): +def print_sql(enable: bool = True) -> None: return cache().set_value("flag_print_sql", enable) -def log(msg): +def log(msg: str) -> None: """Add to `debug_log`. :param msg: Message.""" @@ -397,17 +397,17 @@ def log(msg): def msgprint( - msg, - title=None, - raise_exception=0, - as_table=False, - as_list=False, - indicator=None, - alert=False, - primary_action=None, - is_minimizable=None, - wide=None, -): + msg: str, + title: str | None = None, + raise_exception: bool | type[Exception] = False, + as_table: bool = False, + as_list: bool = False, + indicator: Literal["blue", "green", "orange", "red", "yellow"] | None = None, + alert: bool = False, + primary_action: str = None, + is_minimizable: bool = False, + wide: bool = False, +) -> None: """Print a message to the user (via HTTP response). Messages are sent in the `__server_messages` property in the response JSON and shown in a pop-up / modal. @@ -504,7 +504,14 @@ def clear_last_message(): local.message_log = local.message_log[:-1] -def throw(msg, exc=ValidationError, title=None, is_minimizable=None, wide=None, as_list=False): +def throw( + msg: str, + exc: type[Exception] = ValidationError, + title: str | None = None, + is_minimizable: bool = False, + wide: bool = False, + as_list: bool = False, +) -> None: """Throw execption and show message (`msgprint`). :param msg: Message. @@ -520,12 +527,6 @@ def throw(msg, exc=ValidationError, title=None, is_minimizable=None, wide=None, ) -def emit_js(js, user=False, **kwargs): - if user is False: - user = session.user - publish_realtime("eval_js", js, user=user, **kwargs) - - def create_folder(path, with_init=False): """Create a folder in the given path and add an `__init__.py` file (optional). @@ -540,7 +541,7 @@ def create_folder(path, with_init=False): touch_file(os.path.join(path, "__init__.py")) -def set_user(username): +def set_user(username: str): """Set current user. :param username: **User** name to set as current user.""" @@ -563,7 +564,7 @@ def get_user(): return local.user_perms -def get_roles(username=None): +def get_roles(username=None) -> list[str]: """Returns roles of current user.""" if not local.session: return ["Guest"] @@ -813,7 +814,7 @@ def write_only(): return innfn -def only_for(roles, message=False): +def only_for(roles: list[str] | str, message=False): """Raise `frappe.PermissionError` if the user does not have any of the given **Roles**. :param roles: List of roles to check.""" @@ -846,7 +847,7 @@ def get_domain_data(module): raise -def clear_cache(user=None, doctype=None): +def clear_cache(user: str | None = None, doctype: str | None = None): """Clear **User**, **DocType** or global cache. :param user: If user is given, only user cache is cleared. @@ -979,7 +980,7 @@ def has_website_permission(doc=None, ptype="read", user=None, verbose=False, doc return False -def is_table(doctype): +def is_table(doctype: str) -> bool: """Returns True if `istable` property (indicating child Table) is set for given DocType.""" def get_tables(): @@ -989,14 +990,16 @@ def is_table(doctype): return doctype in tables -def get_precision(doctype, fieldname, currency=None, doc=None): +def get_precision( + doctype: str, fieldname: str, currency: str | None = None, doc: Optional["Document"] = None +) -> int: """Get precision for a given field""" from frappe.model.meta import get_field_precision return get_field_precision(get_meta(doctype).get_field(fieldname), doc, currency) -def generate_hash(txt: Optional[str] = None, length: Optional[int] = None) -> str: +def generate_hash(txt: str | None = None, length: int | None = None) -> str: """Generates random hash for given text + current timestamp + random string.""" import hashlib import time @@ -1018,7 +1021,12 @@ def reset_metadata_version(): return v -def new_doc(doctype, parent_doc=None, parentfield=None, as_dict=False): +def new_doc( + doctype: str, + parent_doc: Optional["Document"] = None, + parentfield: str | None = None, + as_dict: bool = False, +) -> "Document": """Returns a new document of the given DocType with defaults set. :param doctype: DocType of the new document. @@ -1036,6 +1044,16 @@ def set_value(doctype, docname, fieldname, value=None): return frappe.client.set_value(doctype, docname, fieldname, value) +@overload +def get_cached_doc(doctype, docname, _allow_dict=True) -> dict: + ... + + +@overload +def get_cached_doc(*args, **kwargs) -> "Document": + ... + + def get_cached_doc(*args, **kwargs): allow_dict = kwargs.pop("_allow_dict", False) @@ -1076,7 +1094,7 @@ def get_cached_doc(*args, **kwargs): return doc -def can_cache_doc(args): +def can_cache_doc(args) -> str | None: """ Determine if document should be cached based on get_doc params. Returns cache key if doc can be cached, None otherwise. @@ -1093,7 +1111,7 @@ def can_cache_doc(args): return get_document_cache_key(doctype, name) -def get_document_cache_key(doctype, name): +def get_document_cache_key(doctype: str, name: str): return f"{doctype}::{name}" @@ -1109,7 +1127,9 @@ def clear_document_cache(doctype, name): delattr(local, "website_settings") -def get_cached_value(doctype, name, fieldname="name", as_dict=False): +def get_cached_value( + doctype: str, name: str, fieldname: str = "name", as_dict: bool = False +) -> Any: try: doc = get_cached_doc(doctype, name, _allow_dict=True) except DoesNotExistError: @@ -1127,7 +1147,7 @@ def get_cached_value(doctype, name, fieldname="name", as_dict=False): return values -def get_doc(*args, **kwargs): +def get_doc(*args, **kwargs) -> "Document": """Return a `frappe.model.document.Document` object of the given type and name. :param arg1: DocType name as string **or** document JSON. @@ -1186,16 +1206,16 @@ def get_meta_module(doctype): def delete_doc( - doctype=None, - name=None, - force=0, - ignore_doctypes=None, - for_reload=False, - ignore_permissions=False, - flags=None, - ignore_on_trash=False, - ignore_missing=True, - delete_permanently=False, + doctype: str | None = None, + name: str | None = None, + force: bool = False, + ignore_doctypes: list[str] | None = None, + for_reload: bool = False, + ignore_permissions: bool = False, + flags: None = None, + ignore_on_trash: bool = False, + ignore_missing: bool = True, + delete_permanently: bool = False, ): """Delete a document. Calls `frappe.model.delete_doc.delete_doc`. @@ -1238,7 +1258,13 @@ def reload_doctype(doctype, force=False, reset_permissions=False): ) -def reload_doc(module, dt=None, dn=None, force=False, reset_permissions=False): +def reload_doc( + module: str, + dt: str | None = None, + dn: str | None = None, + force: bool = False, + reset_permissions: bool = False, +): """Reload Document from model (`[module]/[doctype]/[name]/[name].json`) files. :param module: Module name. @@ -1289,12 +1315,12 @@ def get_module(modulename): return importlib.import_module(modulename) -def scrub(txt): +def scrub(txt: str) -> str: """Returns sluggified string. e.g. `Sales Order` becomes `sales_order`.""" return cstr(txt).replace(" ", "_").replace("-", "_").lower() -def unscrub(txt): +def unscrub(txt: str) -> str: """Returns titlified string. e.g. `sales_order` becomes `Sales Order`.""" return txt.replace("_", " ").replace("-", " ").title() @@ -1402,7 +1428,7 @@ def get_doc_hooks(): @request_cache -def _load_app_hooks(app_name: Optional[str] = None): +def _load_app_hooks(app_name: str | None = None): hooks = {} apps = [app_name] if app_name else get_installed_apps(sort=True) @@ -1425,7 +1451,7 @@ def _load_app_hooks(app_name: Optional[str] = None): def get_hooks( - hook: str = None, default: Optional[Any] = "_KEEP_DEFAULT_LIST", app_name: str = None + hook: str = None, default: Any | None = "_KEEP_DEFAULT_LIST", app_name: str = None ) -> _dict: """Get hooks via `app/hooks.py` @@ -1508,7 +1534,7 @@ def get_file_items(path, raise_not_found=False, ignore_empty_lines=True): def get_file_json(path): """Read a file and return parsed JSON object.""" - with open(path, "r") as f: + with open(path) as f: return json.load(f) @@ -1518,15 +1544,15 @@ def read_file(path, raise_not_found=False): path = path.encode("utf-8") if os.path.exists(path): - with open(path, "r") as f: + with open(path) as f: return as_unicode(f.read()) elif raise_not_found: - raise IOError("{} Not Found".format(path)) + raise OSError(f"{path} Not Found") else: return None -def get_attr(method_string): +def get_attr(method_string: str) -> Any: """Get python method object from its name.""" app_name = method_string.split(".")[0] if ( @@ -1541,7 +1567,7 @@ def get_attr(method_string): return getattr(get_module(modulename), methodname) -def call(fn, *args, **kwargs): +def call(fn: str | Callable, *args, **kwargs): """Call a function and match arguments.""" if isinstance(fn, str): fn = get_attr(fn) @@ -1551,7 +1577,7 @@ def call(fn, *args, **kwargs): return fn(*args, **newargs) -def get_newargs(fn: Callable, kwargs: Dict[str, Any]) -> Dict[str, Any]: +def get_newargs(fn: Callable, kwargs: dict[str, Any]) -> dict[str, Any]: """Remove any kwargs that are not supported by the function. Example: @@ -1650,7 +1676,7 @@ def import_doc(path): import_doc(path) -def copy_doc(doc, ignore_no_copy=True): +def copy_doc(doc: "Document", ignore_no_copy: bool = True) -> "Document": """No_copy fields also get copied.""" import copy @@ -1788,8 +1814,8 @@ def redirect_to_message(title, html, http_status_code=None, context=None, indica if indicator_color: message["context"].update({"indicator_color": indicator_color}) - cache().set_value("message_id:{0}".format(message_id), message, expires_in_sec=60) - location = "/message?id={0}".format(message_id) + cache().set_value(f"message_id:{message_id}", message, expires_in_sec=60) + location = f"/message?id={message_id}" if not getattr(local, "is_ajax", False): local.response["type"] = "redirect" @@ -1875,7 +1901,7 @@ def get_value(*args, **kwargs): return db.get_value(*args, **kwargs) -def as_json(obj: Union[Dict, List], indent=1, separators=None) -> str: +def as_json(obj: dict | list, indent=1, separators=None) -> str: from frappe.utils.response import json_handler if separators is None: @@ -1906,7 +1932,7 @@ def get_test_records(doctype): get_module_path(get_doctype_module(doctype)), "doctype", scrub(doctype), "test_records.json" ) if os.path.exists(path): - with open(path, "r") as f: + with open(path) as f: return json.loads(f.read()) else: return [] @@ -2186,7 +2212,7 @@ def get_desk_link(doctype, name): def bold(text): - return "{0}".format(text) + return f"{text}" def safe_eval(code, eval_globals=None, eval_locals=None): @@ -2214,10 +2240,10 @@ def safe_eval(code, eval_globals=None, eval_locals=None): for attribute in UNSAFE_ATTRIBUTES: if attribute in code: - throw('Illegal rule {0}. Cannot use "{1}"'.format(bold(code), attribute)) + throw(f'Illegal rule {bold(code)}. Cannot use "{attribute}"') if "__" in code: - throw('Illegal rule {0}. Cannot use "__"'.format(bold(code))) + throw(f'Illegal rule {bold(code)}. Cannot use "__"') if not eval_globals: eval_globals = {} diff --git a/frappe/api.py b/frappe/api.py index 32e19a1b43..1048468077 100644 --- a/frappe/api.py +++ b/frappe/api.py @@ -167,7 +167,7 @@ def validate_auth(): """ Authenticate and sets user for the request. """ - authorization_header = frappe.get_request_header("Authorization", str()).split(" ") + authorization_header = frappe.get_request_header("Authorization", "").split(" ") if len(authorization_header) == 2: validate_oauth(authorization_header) diff --git a/frappe/app.py b/frappe/app.py index f8c81478c0..b9db59cdb1 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE @@ -34,7 +33,7 @@ SAFE_HTTP_METHODS = ("GET", "HEAD", "OPTIONS") UNSAFE_HTTP_METHODS = ("POST", "PUT", "DELETE", "PATCH") -class RequestContext(object): +class RequestContext: def __init__(self, environ): self.request = Request(environ) @@ -223,10 +222,6 @@ def handle_exception(e): or (frappe.local.request.path.startswith("/api/") and not accept_header.startswith("text")) ) - if frappe.conf.get("developer_mode"): - # don't fail silently - print(frappe.get_traceback()) - if respond_as_json: # handle ajax responses first # if the request is ajax, send back the trace or error message @@ -290,6 +285,10 @@ def handle_exception(e): if return_as_message: response = get_response("message", http_status_code=http_status_code) + if frappe.conf.get("developer_mode") and not respond_as_json: + # don't fail silently for non-json response errors + print(frappe.get_traceback()) + return response @@ -331,12 +330,10 @@ def serve( if not os.environ.get("NO_STATICS"): application = SharedDataMiddleware( - application, {str("/assets"): str(os.path.join(sites_path, "assets"))} + application, {"/assets": str(os.path.join(sites_path, "assets"))} ) - application = StaticDataMiddleware( - application, {str("/files"): str(os.path.abspath(sites_path))} - ) + application = StaticDataMiddleware(application, {"/files": str(os.path.abspath(sites_path))}) application.debug = True application.config = {"SERVER_NAME": "localhost:8000"} diff --git a/frappe/auth.py b/frappe/auth.py index 80141d1d6c..3737681d71 100644 --- a/frappe/auth.py +++ b/frappe/auth.py @@ -471,7 +471,7 @@ def get_login_attempt_tracker(user_name: str, raise_locked_exception: bool = Tru return tracker -class LoginAttemptTracker(object): +class LoginAttemptTracker: """Track login attemts of a user. Lock the account for s number of seconds if there have been n consecutive unsuccessful attempts to log in. diff --git a/frappe/automation/doctype/assignment_rule/assignment_rule.py b/frappe/automation/doctype/assignment_rule/assignment_rule.py index 0ca64e54c2..508ed317c6 100644 --- a/frappe/automation/doctype/assignment_rule/assignment_rule.py +++ b/frappe/automation/doctype/assignment_rule/assignment_rule.py @@ -1,7 +1,7 @@ # Copyright (c) 2022, Frappe Technologies and contributors # License: MIT. See LICENSE -from typing import Dict, Iterable, List +from collections.abc import Iterable import frappe from frappe import _ @@ -157,7 +157,7 @@ class AssignmentRule(Document): return assignment_days and today not in assignment_days -def get_assignments(doc) -> List[Dict]: +def get_assignments(doc) -> list[dict]: return frappe.get_all( "ToDo", fields=["name", "assignment_rule"], @@ -228,7 +228,7 @@ def apply(doc=None, method=None, doctype=None, name=None): ) # multiple auto assigns - assignment_rule_docs: List[AssignmentRule] = [ + assignment_rule_docs: list[AssignmentRule] = [ frappe.get_cached_doc("Assignment Rule", d.get("name")) for d in assignment_rules ] @@ -356,11 +356,11 @@ def update_due_date(doc, state=None): todo_doc.save(ignore_permissions=True) -def get_assignment_rules() -> List[str]: +def get_assignment_rules() -> list[str]: return frappe.get_all("Assignment Rule", filters={"disabled": 0}, pluck="document_type") -def get_repeated(values: Iterable) -> List: +def get_repeated(values: Iterable) -> list: unique = set() repeated = set() diff --git a/frappe/automation/doctype/assignment_rule_day/assignment_rule_day.py b/frappe/automation/doctype/assignment_rule_day/assignment_rule_day.py index 2a7e6dd66f..5a1af94696 100644 --- a/frappe/automation/doctype/assignment_rule_day/assignment_rule_day.py +++ b/frappe/automation/doctype/assignment_rule_day/assignment_rule_day.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/automation/doctype/assignment_rule_user/assignment_rule_user.py b/frappe/automation/doctype/assignment_rule_user/assignment_rule_user.py index 3f47f3c866..8b848589c3 100644 --- a/frappe/automation/doctype/assignment_rule_user/assignment_rule_user.py +++ b/frappe/automation/doctype/assignment_rule_user/assignment_rule_user.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/automation/doctype/auto_repeat/auto_repeat.py b/frappe/automation/doctype/auto_repeat/auto_repeat.py index d3399f7726..0442be0976 100644 --- a/frappe/automation/doctype/auto_repeat/auto_repeat.py +++ b/frappe/automation/doctype/auto_repeat/auto_repeat.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/automation/doctype/auto_repeat/test_auto_repeat.py b/frappe/automation/doctype/auto_repeat/test_auto_repeat.py index e1db7ca6d1..ee0addf847 100644 --- a/frappe/automation/doctype/auto_repeat/test_auto_repeat.py +++ b/frappe/automation/doctype/auto_repeat/test_auto_repeat.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest @@ -200,7 +199,7 @@ class TestAutoRepeat(unittest.TestCase): # next_schedule_date is set as on or after current date # it should not be a previous month's date - self.assertTrue((doc.next_schedule_date >= current_date)) + self.assertTrue(doc.next_schedule_date >= current_date) todo = frappe.get_doc( dict( diff --git a/frappe/automation/doctype/auto_repeat_day/auto_repeat_day.py b/frappe/automation/doctype/auto_repeat_day/auto_repeat_day.py index 95d75bf9da..6453f2e80d 100644 --- a/frappe/automation/doctype/auto_repeat_day/auto_repeat_day.py +++ b/frappe/automation/doctype/auto_repeat_day/auto_repeat_day.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/automation/doctype/milestone/milestone.py b/frappe/automation/doctype/milestone/milestone.py index 4059a2eb73..40d6fae989 100644 --- a/frappe/automation/doctype/milestone/milestone.py +++ b/frappe/automation/doctype/milestone/milestone.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/automation/doctype/milestone/test_milestone.py b/frappe/automation/doctype/milestone/test_milestone.py index 1824220497..5ac0754e5a 100644 --- a/frappe/automation/doctype/milestone/test_milestone.py +++ b/frappe/automation/doctype/milestone/test_milestone.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/automation/doctype/milestone_tracker/milestone_tracker.py b/frappe/automation/doctype/milestone_tracker/milestone_tracker.py index 16b2fe9204..5388797b80 100644 --- a/frappe/automation/doctype/milestone_tracker/milestone_tracker.py +++ b/frappe/automation/doctype/milestone_tracker/milestone_tracker.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/automation/doctype/milestone_tracker/test_milestone_tracker.py b/frappe/automation/doctype/milestone_tracker/test_milestone_tracker.py index 4e53072348..2b48a76805 100644 --- a/frappe/automation/doctype/milestone_tracker/test_milestone_tracker.py +++ b/frappe/automation/doctype/milestone_tracker/test_milestone_tracker.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/boot.py b/frappe/boot.py index 6cd86dc4fc..a0a93bd497 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -77,6 +77,8 @@ def get_bootinfo(): # add docs bootinfo.docs = doclist + load_country_doc(bootinfo) + load_currency_docs(bootinfo) for method in hooks.boot_session or []: frappe.get_attr(method)(bootinfo) @@ -417,3 +419,34 @@ def get_translatable_doctypes(): "Property Setter", {"property": "translate_link_fields", "value": "1"}, pluck="doc_type" ) return dts + custom_dts + + +def load_country_doc(bootinfo): + country = frappe.db.get_default("country") + if not country: + return + try: + bootinfo.docs.append(frappe.get_cached_doc("Country", country)) + except Exception: + pass + + +def load_currency_docs(bootinfo): + currency = frappe.qb.DocType("Currency") + + currency_docs = ( + frappe.qb.from_(currency) + .select( + currency.name, + currency.fraction, + currency.fraction_units, + currency.number_format, + currency.smallest_currency_fraction_value, + currency.symbol, + currency.symbol_on_right, + ) + .where(currency.enabled == 1) + .run(as_dict=1, update={"doctype": ":Currency"}) + ) + + bootinfo.docs += currency_docs diff --git a/frappe/build.py b/frappe/build.py index a7fdb47677..e66da4bd79 100644 --- a/frappe/build.py +++ b/frappe/build.py @@ -200,7 +200,7 @@ def symlink(target, link_name, overwrite=False): try: # Pre-empt os.replace on a directory with a nicer message if os.path.isdir(link_name): - raise IsADirectoryError("Cannot symlink over existing directory: '{}'".format(link_name)) + raise IsADirectoryError(f"Cannot symlink over existing directory: '{link_name}'") try: os.replace(temp_link_name, link_name) except AttributeError: @@ -239,10 +239,10 @@ def bundle( make_asset_dirs(hard_link=hard_link) mode = "production" if mode == "production" else "build" - command = "yarn run {mode}".format(mode=mode) + command = f"yarn run {mode}" if apps: - command += " --apps {apps}".format(apps=apps) + command += f" --apps {apps}" if skip_frappe: command += " --skip_frappe" @@ -263,7 +263,7 @@ def watch(apps=None): command = "yarn run watch" if apps: - command += " --apps {apps}".format(apps=apps) + command += f" --apps {apps}" live_reload = frappe.utils.cint(os.environ.get("LIVE_RELOAD", frappe.conf.live_reload)) diff --git a/frappe/client.py b/frappe/client.py index d5dc890f56..bd5c3b275b 100644 --- a/frappe/client.py +++ b/frappe/client.py @@ -349,13 +349,13 @@ def get_js(items): frappe.throw(_("Invalid file path: {0}").format("/".join(src))) contentpath = os.path.join(frappe.local.sites_path, *src) - with open(contentpath, "r") as srcfile: + with open(contentpath) as srcfile: code = frappe.utils.cstr(srcfile.read()) if frappe.local.lang != "en": messages = frappe.get_lang_dict("jsfile", contentpath) messages = json.dumps(messages) - code += "\n\n$.extend(frappe._messages, {})".format(messages) + code += f"\n\n$.extend(frappe._messages, {messages})" out.append(code) diff --git a/frappe/commands/scheduler.py b/frappe/commands/scheduler.py index b383eabddb..e481676088 100755 --- a/frappe/commands/scheduler.py +++ b/frappe/commands/scheduler.py @@ -99,7 +99,7 @@ def scheduler(context, state, site=None): frappe.utils.scheduler.enable_scheduler() frappe.db.commit() - print("Scheduler {0}d for site {1}".format(state, site)) + print(f"Scheduler {state}d for site {site}") finally: frappe.destroy() @@ -167,7 +167,7 @@ def purge_jobs(site=None, queue=None, event=None): frappe.init(site or "") count = purge_pending_jobs(event=event, site=site, queue=queue) - print("Purged {} jobs".format(count)) + print(f"Purged {count} jobs") @click.command("schedule") @@ -203,11 +203,11 @@ def ready_for_migration(context, site=None): pending_jobs = get_pending_jobs(site=site) if pending_jobs: - print("NOT READY for migration: site {0} has pending background jobs".format(site)) + print(f"NOT READY for migration: site {site} has pending background jobs") sys.exit(1) else: - print("READY for migration: site {0} does not have any background jobs".format(site)) + print(f"READY for migration: site {site} does not have any background jobs") return 0 finally: diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 4db143b076..62451b6013 100644 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -257,7 +257,7 @@ def restore( os.remove(private) _backup.decryption_rollback() - success_message = "Site {0} has been restored{1}".format( + success_message = "Site {} has been restored{}".format( site, " with files" if (with_public_files or with_private_files) else "" ) click.secho(success_message, fg="green") @@ -414,12 +414,12 @@ def install_app(context, apps, force=False): try: _install_app(app, verbose=context.verbose, force=force) except frappe.IncompatibleApp as err: - err_msg = ":\n{}".format(err) if str(err) else "" - print("App {} is Incompatible with Site {}{}".format(app, site, err_msg)) + err_msg = f":\n{err}" if str(err) else "" + print(f"App {app} is Incompatible with Site {site}{err_msg}") exit_code = 1 except Exception as err: - err_msg = ": {}\n{}".format(str(err), frappe.get_traceback()) - print("An error occurred while installing {}{}".format(app, err_msg)) + err_msg = f": {str(err)}\n{frappe.get_traceback()}" + print(f"An error occurred while installing {app}{err_msg}") exit_code = 1 frappe.destroy() @@ -449,8 +449,8 @@ def list_apps(context, format): apps = frappe.get_single("Installed Applications").installed_applications if apps: - name_len, ver_len = [max([len(x.get(y)) for x in apps]) for y in ["app_name", "app_version"]] - template = "{{0:{0}}} {{1:{1}}} {{2}}".format(name_len, ver_len) + name_len, ver_len = (max(len(x.get(y)) for x in apps) for y in ["app_name", "app_version"]) + template = f"{{0:{name_len}}} {{1:{ver_len}}} {{2}}" installed_applications = [ template.format(app.app_name, app.app_version, app.git_branch) for app in apps @@ -608,7 +608,7 @@ def reload_doctype(context, doctype): def add_to_hosts(context): "Add site to hosts" for site in context.sites: - frappe.commands.popen("echo 127.0.0.1\t{0} | sudo tee -a /etc/hosts".format(site)) + frappe.commands.popen(f"echo 127.0.0.1\t{site} | sudo tee -a /etc/hosts") if not context.sites: raise SiteNotSpecifiedError @@ -624,9 +624,9 @@ def use(site, sites_path="."): if os.path.exists(os.path.join(sites_path, site)): with open(os.path.join(sites_path, "currentsite.txt"), "w") as sitefile: sitefile.write(site) - print("Current Site set to {}".format(site)) + print(f"Current Site set to {site}") else: - print("Site {} does not exist".format(site)) + print(f"Site {site} does not exist") @click.command("backup") @@ -700,7 +700,7 @@ def backup( ) except Exception: click.secho( - "Backup failed for Site {0}. Database or site_config.json may be corrupted".format(site), + f"Backup failed for Site {site}. Database or site_config.json may be corrupted", fg="red", ) if verbose: @@ -714,7 +714,7 @@ def backup( odb.print_summary() click.secho( - "Backup for Site {0} has been successfully completed{1}".format( + "Backup for Site {} has been successfully completed{}".format( site, " with files" if with_files else "" ), fg="green", @@ -831,8 +831,8 @@ def _drop_site( else: messages = [ "=" * 80, - "Error: The operation has stopped because backup of {0}'s database failed.".format(site), - "Reason: {0}\n".format(str(err)), + 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), ] @@ -1082,7 +1082,7 @@ def build_search_index(context): if not site: raise SiteNotSpecifiedError - print("Building search index for {}".format(site)) + print(f"Building search index for {site}") frappe.init(site=site) frappe.connect() try: diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index a6bf48fac9..e8d5c3809a 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -387,7 +387,7 @@ def import_doc(context, path, force=False): if not os.path.exists(path): path = os.path.join("..", path) if not os.path.exists(path): - print("Invalid path {0}".format(path)) + print(f"Invalid path {path}") sys.exit(1) for site in context.sites: @@ -471,7 +471,7 @@ def bulk_rename(context, doctype, path): site = get_site(context) - with open(path, "r") as csvfile: + with open(path) as csvfile: rows = read_csv_content(csvfile.read()) frappe.init(site=site) @@ -566,7 +566,7 @@ def jupyter(context): try: os.stat(jupyter_notebooks_path) except OSError: - print("Creating folder to keep jupyter notebooks at {}".format(jupyter_notebooks_path)) + print(f"Creating folder to keep jupyter notebooks at {jupyter_notebooks_path}") os.mkdir(jupyter_notebooks_path) bin_path = os.path.abspath("../env/bin") print( @@ -585,9 +585,9 @@ frappe.db.connect() ) ) os.execv( - "{0}/jupyter".format(bin_path), + f"{bin_path}/jupyter", [ - "{0}/jupyter".format(bin_path), + f"{bin_path}/jupyter", "notebook", jupyter_notebooks_path, ], @@ -780,7 +780,7 @@ def run_tests( if not (allow_tests or os.environ.get("CI")): click.secho("Testing is disabled for the site!", bold=True) click.secho("You can enable tests by entering following command:") - click.secho("bench --site {0} set-config allow_tests true".format(site), fg="green") + click.secho(f"bench --site {site} set-config allow_tests true", fg="green") return frappe.init(site=site) @@ -963,7 +963,7 @@ def request(context, args=None, path=None): if args.startswith("/api/method"): frappe.local.form_dict.cmd = args.split("?")[0].split("/")[-1] elif path: - with open(os.path.join("..", path), "r") as f: + with open(os.path.join("..", path)) as f: args = json.loads(f.read()) frappe.local.form_dict = frappe._dict(args) diff --git a/frappe/contacts/address_and_contact.py b/frappe/contacts/address_and_contact.py index 1c5803ffea..4df32c6705 100644 --- a/frappe/contacts/address_and_contact.py +++ b/frappe/contacts/address_and_contact.py @@ -3,7 +3,6 @@ import functools import re -from typing import Dict, List import frappe from frappe import _ @@ -117,9 +116,7 @@ def get_permission_query_conditions(doctype): # when everything is not permitted for df in links.get("not_permitted_links"): # like ifnull(customer, '')='' and ifnull(supplier, '')='' - conditions.append( - "ifnull(`tab{doctype}`.`{fieldname}`, '')=''".format(doctype=doctype, fieldname=df.fieldname) - ) + conditions.append(f"ifnull(`tab{doctype}`.`{df.fieldname}`, '')=''") return "( " + " and ".join(conditions) + " )" @@ -128,9 +125,7 @@ def get_permission_query_conditions(doctype): for df in links.get("permitted_links"): # like ifnull(customer, '')!='' or ifnull(supplier, '')!='' - conditions.append( - "ifnull(`tab{doctype}`.`{fieldname}`, '')!=''".format(doctype=doctype, fieldname=df.fieldname) - ) + conditions.append(f"ifnull(`tab{doctype}`.`{df.fieldname}`, '')!=''") return "( " + " or ".join(conditions) + " )" @@ -171,8 +166,8 @@ def delete_contact_and_address(doctype, docname): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs def filter_dynamic_link_doctypes( - doctype, txt: str, searchfield, start, page_len, filters: Dict -) -> List[List[str]]: + doctype, txt: str, searchfield, start, page_len, filters: dict +) -> list[list[str]]: from frappe.permissions import get_doctypes_with_read txt = txt or "" diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index c7564e8866..42dbdd6177 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -236,7 +235,7 @@ def address_query(doctype, txt, searchfield, start, page_len, filters): meta = frappe.get_meta("Address") for fieldname, value in filters.items(): if meta.get_field(fieldname) or fieldname in frappe.db.DEFAULT_COLUMNS: - condition += " and {field}={value}".format(field=fieldname, value=frappe.db.escape(value)) + condition += f" and {fieldname}={frappe.db.escape(value)}" searchfields = meta.get_search_fields() @@ -246,9 +245,9 @@ def address_query(doctype, txt, searchfield, start, page_len, filters): search_condition = "" for field in searchfields: if search_condition == "": - search_condition += "`tabAddress`.`{field}` like %(txt)s".format(field=field) + search_condition += f"`tabAddress`.`{field}` like %(txt)s" else: - search_condition += " or `tabAddress`.`{field}` like %(txt)s".format(field=field) + search_condition += f" or `tabAddress`.`{field}` like %(txt)s" return frappe.db.sql( """select diff --git a/frappe/contacts/doctype/address/test_address.py b/frappe/contacts/doctype/address/test_address.py index 4a6e6e53f7..edcf87f5bc 100644 --- a/frappe/contacts/doctype/address/test_address.py +++ b/frappe/contacts/doctype/address/test_address.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/contacts/doctype/address_template/address_template.py b/frappe/contacts/doctype/address_template/address_template.py index 85e9a986ef..a8806b336b 100644 --- a/frappe/contacts/doctype/address_template/address_template.py +++ b/frappe/contacts/doctype/address_template/address_template.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/contacts/doctype/address_template/test_address_template.py b/frappe/contacts/doctype/address_template/test_address_template.py index 699de5ada0..8045313c69 100644 --- a/frappe/contacts/doctype/address_template/test_address_template.py +++ b/frappe/contacts/doctype/address_template/test_address_template.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 4036cda853..a17f46216b 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -290,7 +290,7 @@ def get_contact_with_phone_number(number): return contacts = frappe.get_all( - "Contact Phone", filters=[["phone", "like", "%{0}".format(number)]], fields=["parent"], limit=1 + "Contact Phone", filters=[["phone", "like", f"%{number}"]], fields=["parent"], limit=1 ) return contacts[0].parent if contacts else None diff --git a/frappe/contacts/doctype/contact/test_contact.py b/frappe/contacts/doctype/contact/test_contact.py index 7ca47476e8..bf0d1037db 100644 --- a/frappe/contacts/doctype/contact/test_contact.py +++ b/frappe/contacts/doctype/contact/test_contact.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/contacts/doctype/contact_email/contact_email.py b/frappe/contacts/doctype/contact_email/contact_email.py index ed794ac06c..b6be852e57 100644 --- a/frappe/contacts/doctype/contact_email/contact_email.py +++ b/frappe/contacts/doctype/contact_email/contact_email.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/contacts/doctype/contact_phone/contact_phone.py b/frappe/contacts/doctype/contact_phone/contact_phone.py index 2a842c9c9e..ba6cd89834 100644 --- a/frappe/contacts/doctype/contact_phone/contact_phone.py +++ b/frappe/contacts/doctype/contact_phone/contact_phone.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/contacts/doctype/gender/gender.py b/frappe/contacts/doctype/gender/gender.py index 8e9951eaf9..fa38a5a6b0 100644 --- a/frappe/contacts/doctype/gender/gender.py +++ b/frappe/contacts/doctype/gender/gender.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/contacts/doctype/gender/test_gender.py b/frappe/contacts/doctype/gender/test_gender.py index 6b795749ee..c8df3b566d 100644 --- a/frappe/contacts/doctype/gender/test_gender.py +++ b/frappe/contacts/doctype/gender/test_gender.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/contacts/doctype/salutation/salutation.py b/frappe/contacts/doctype/salutation/salutation.py index 57fb2d6abc..66469c4700 100644 --- a/frappe/contacts/doctype/salutation/salutation.py +++ b/frappe/contacts/doctype/salutation/salutation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/contacts/doctype/salutation/test_salutation.py b/frappe/contacts/doctype/salutation/test_salutation.py index 5149ced3dd..2c35e5bd2b 100644 --- a/frappe/contacts/doctype/salutation/test_salutation.py +++ b/frappe/contacts/doctype/salutation/test_salutation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/api/file.py b/frappe/core/api/file.py index e558f2f7e3..ec305aff4f 100644 --- a/frappe/core/api/file.py +++ b/frappe/core/api/file.py @@ -1,5 +1,4 @@ import json -from typing import Dict, List import frappe from frappe.core.doctype.file.file import File, setup_folder_path @@ -14,7 +13,7 @@ def unzip_file(name: str): @frappe.whitelist() -def get_attached_images(doctype: str, names: List[str]) -> frappe._dict: +def get_attached_images(doctype: str, names: list[str]) -> frappe._dict: """get list of image urls attached in form returns {name: ['image.jpg', 'image.png']}""" @@ -40,7 +39,7 @@ def get_attached_images(doctype: str, names: List[str]) -> frappe._dict: @frappe.whitelist() -def get_files_in_folder(folder: str, start: int = 0, page_length: int = 20) -> Dict: +def get_files_in_folder(folder: str, start: int = 0, page_length: int = 20) -> dict: start = cint(start) page_length = cint(page_length) @@ -66,7 +65,7 @@ def get_files_in_folder(folder: str, start: int = 0, page_length: int = 20) -> D @frappe.whitelist() -def get_files_by_search_text(text: str) -> List[Dict]: +def get_files_by_search_text(text: str) -> list[dict]: if not text: return [] @@ -102,7 +101,7 @@ def create_new_folder(file_name: str, folder: str) -> File: @frappe.whitelist() -def move_file(file_list: List[File], new_parent: str, old_parent: str) -> None: +def move_file(file_list: list[File], new_parent: str, old_parent: str) -> None: if isinstance(file_list, str): file_list = json.loads(file_list) diff --git a/frappe/core/doctype/access_log/test_access_log.py b/frappe/core/doctype/access_log/test_access_log.py index 983e3cb5e4..ee0422e11a 100644 --- a/frappe/core/doctype/access_log/test_access_log.py +++ b/frappe/core/doctype/access_log/test_access_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE @@ -28,7 +27,7 @@ class TestAccessLog(unittest.TestCase): "User", frappe.session.user, fieldname="api_secret" ) api_key = frappe.db.get_value("User", "Administrator", "api_key") - self.header = {"Authorization": "token {}:{}".format(api_key, generated_secret)} + self.header = {"Authorization": f"token {api_key}:{generated_secret}"} self.test_html_template = """ diff --git a/frappe/core/doctype/activity_log/feed.py b/frappe/core/doctype/activity_log/feed.py index 3e29154242..eb040927e1 100644 --- a/frappe/core/doctype/activity_log/feed.py +++ b/frappe/core/doctype/activity_log/feed.py @@ -74,9 +74,7 @@ def get_feed_match_conditions(user=None, doctype="Comment"): user_permissions = frappe.permissions.get_user_permissions(user) can_read = frappe.get_user().get_can_read() - can_read_doctypes = [ - "'{}'".format(dt) for dt in list(set(can_read) - set(list(user_permissions))) - ] + can_read_doctypes = [f"'{dt}'" for dt in list(set(can_read) - set(list(user_permissions)))] if can_read_doctypes: conditions += [ diff --git a/frappe/core/doctype/activity_log/test_activity_log.py b/frappe/core/doctype/activity_log/test_activity_log.py index f5f94dc44b..c362fca521 100644 --- a/frappe/core/doctype/activity_log/test_activity_log.py +++ b/frappe/core/doctype/activity_log/test_activity_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import time diff --git a/frappe/core/doctype/block_module/block_module.py b/frappe/core/doctype/block_module/block_module.py index 456df5037c..b9de5b325e 100644 --- a/frappe/core/doctype/block_module/block_module.py +++ b/frappe/core/doctype/block_module/block_module.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/comment/comment.py b/frappe/core/doctype/comment/comment.py index 1456f1ec93..dab9cfbfe4 100644 --- a/frappe/core/doctype/comment/comment.py +++ b/frappe/core/doctype/comment/comment.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE import json @@ -51,7 +50,7 @@ class Comment(Document): return frappe.publish_realtime( - "update_docinfo_for_{}_{}".format(self.reference_doctype, self.reference_name), + f"update_docinfo_for_{self.reference_doctype}_{self.reference_name}", {"doc": self.as_dict(), "key": key, "action": action}, after_commit=True, ) @@ -183,7 +182,7 @@ def update_comments_in_parent(reference_doctype, reference_name, _comments): try: # use sql, so that we do not mess with the timestamp frappe.db.sql( - """update `tab{0}` set `_comments`=%s where name=%s""".format(reference_doctype), # nosec + f"""update `tab{reference_doctype}` set `_comments`=%s where name=%s""", # nosec (json.dumps(_comments[-100:]), reference_name), ) diff --git a/frappe/core/doctype/comment/test_comment.py b/frappe/core/doctype/comment/test_comment.py index 3072f8b5b9..bedcea6e7e 100644 --- a/frappe/core/doctype/comment/test_comment.py +++ b/frappe/core/doctype/comment/test_comment.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import json diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 9b86f18726..fac8ac74b9 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -3,7 +3,6 @@ from collections import Counter from email.utils import getaddresses -from typing import List from urllib.parse import unquote from parse import compile @@ -204,7 +203,7 @@ class Communication(Document, CommunicationEmailMixin): """ emails = split_emails(emails) if isinstance(emails, str) else (emails or []) if exclude_displayname: - return [email.lower() for email in set([parse_addr(email)[1] for email in emails]) if email] + return [email.lower() for email in {parse_addr(email)[1] for email in emails} if email] return [email.lower() for email in set(emails) if email] def to_list(self, exclude_displayname=True): @@ -229,7 +228,7 @@ class Communication(Document, CommunicationEmailMixin): def notify_change(self, action): frappe.publish_realtime( - "update_docinfo_for_{}_{}".format(self.reference_doctype, self.reference_name), + f"update_docinfo_for_{self.reference_doctype}_{self.reference_name}", {"doc": self.as_dict(), "key": "communications", "action": action}, after_commit=True, ) @@ -425,7 +424,7 @@ def get_permission_query_conditions_for_communication(user): ) -def get_contacts(email_strings: List[str], auto_create_contact=False) -> List[str]: +def get_contacts(email_strings: list[str], auto_create_contact=False) -> list[str]: email_addrs = get_emails(email_strings) contacts = [] for email in email_addrs: @@ -437,9 +436,7 @@ def get_contacts(email_strings: List[str], auto_create_contact=False) -> List[st first_name = frappe.unscrub(email_parts[0]) try: - contact_name = ( - "{0}-{1}".format(first_name, email_parts[1]) if first_name == "Contact" else first_name - ) + contact_name = f"{first_name}-{email_parts[1]}" if first_name == "Contact" else first_name contact = frappe.get_doc( {"doctype": "Contact", "first_name": contact_name, "name": contact_name} ) @@ -455,7 +452,7 @@ def get_contacts(email_strings: List[str], auto_create_contact=False) -> List[st return contacts -def get_emails(email_strings: List[str]) -> List[str]: +def get_emails(email_strings: list[str]) -> list[str]: email_addrs = [] for email_string in email_strings: @@ -522,7 +519,7 @@ def get_email_without_link(email): except IndexError: return email - return "{0}@{1}".format(email_id, email_host) + return f"{email_id}@{email_host}" def update_parent_document_on_communication(doc): diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 2c8a65fafe..c5585fd463 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -2,7 +2,7 @@ # License: MIT. See LICENSE import json -from typing import TYPE_CHECKING, Dict +from typing import TYPE_CHECKING import frappe import frappe.email.smtp @@ -45,7 +45,7 @@ def make( email_template=None, communication_type=None, **kwargs, -) -> Dict[str, str]: +) -> dict[str, str]: """Make a new communication. Checks for email permissions for specified Document. :param doctype: Reference DocType. @@ -122,7 +122,7 @@ def _make( email_template=None, communication_type=None, add_signature=True, -) -> Dict[str, str]: +) -> dict[str, str]: """Internal method to make a new communication that ignores Permission checks.""" sender = sender or get_formatted_email(frappe.session.user) diff --git a/frappe/core/doctype/communication/mixins.py b/frappe/core/doctype/communication/mixins.py index 0263cfeac5..695b8bebae 100644 --- a/frappe/core/doctype/communication/mixins.py +++ b/frappe/core/doctype/communication/mixins.py @@ -1,5 +1,3 @@ -from typing import List - import frappe from frappe import _ from frappe.core.utils import get_parent_doc @@ -201,7 +199,7 @@ class CommunicationEmailMixin: return _("Leave this conversation") return "" - def exclude_emails_list(self, is_inbound_mail_communcation=False, include_sender=False) -> List: + def exclude_emails_list(self, is_inbound_mail_communcation=False, include_sender=False) -> list: """List of mail id's excluded while sending mail.""" all_ids = self.get_all_email_addresses(exclude_displayname=True) diff --git a/frappe/core/doctype/communication/test_communication.py b/frappe/core/doctype/communication/test_communication.py index a338295374..77f83b7f91 100644 --- a/frappe/core/doctype/communication/test_communication.py +++ b/frappe/core/doctype/communication/test_communication.py @@ -236,7 +236,7 @@ class TestCommunication(unittest.TestCase): "communication_medium": "Email", "subject": "Document Link in Email", "sender": "comm_sender@example.com", - "recipients": "comm_recipient+{0}+{1}@example.com".format(quote("Note"), quote(note.name)), + "recipients": "comm_recipient+{}+{}@example.com".format(quote("Note"), quote(note.name)), } ).insert(ignore_permissions=True) diff --git a/frappe/core/doctype/communication_link/communication_link.py b/frappe/core/doctype/communication_link/communication_link.py index 21b6a7828a..07633ad174 100644 --- a/frappe/core/doctype/communication_link/communication_link.py +++ b/frappe/core/doctype/communication_link/communication_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/custom_docperm/custom_docperm.py b/frappe/core/doctype/custom_docperm/custom_docperm.py index 23815e9bf6..e24c765df4 100644 --- a/frappe/core/doctype/custom_docperm/custom_docperm.py +++ b/frappe/core/doctype/custom_docperm/custom_docperm.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/custom_docperm/test_custom_docperm.py b/frappe/core/doctype/custom_docperm/test_custom_docperm.py index 51923718b6..4aa04f0223 100644 --- a/frappe/core/doctype/custom_docperm/test_custom_docperm.py +++ b/frappe/core/doctype/custom_docperm/test_custom_docperm.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/custom_role/custom_role.py b/frappe/core/doctype/custom_role/custom_role.py index dd215dea17..4d96def662 100644 --- a/frappe/core/doctype/custom_role/custom_role.py +++ b/frappe/core/doctype/custom_role/custom_role.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/custom_role/test_custom_role.py b/frappe/core/doctype/custom_role/test_custom_role.py index 9c12bddd26..79c66255c0 100644 --- a/frappe/core/doctype/custom_role/test_custom_role.py +++ b/frappe/core/doctype/custom_role/test_custom_role.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/data_export/data_export.py b/frappe/core/doctype/data_export/data_export.py index 268182fbd4..b27966aa3d 100644 --- a/frappe/core/doctype/data_export/data_export.py +++ b/frappe/core/doctype/data_export/data_export.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/data_export/exporter.py b/frappe/core/doctype/data_export/exporter.py index 514be16694..b7f69ab43d 100644 --- a/frappe/core/doctype/data_export/exporter.py +++ b/frappe/core/doctype/data_export/exporter.py @@ -331,7 +331,7 @@ class DataExporter: order_by = None table_columns = frappe.db.get_table_columns(self.parent_doctype) if "lft" in table_columns and "rgt" in table_columns: - order_by = "`tab{doctype}`.`lft` asc".format(doctype=self.parent_doctype) + order_by = f"`tab{self.parent_doctype}`.`lft` asc" # get permitted data only self.data = frappe.get_list( self.doctype, fields=["*"], filters=self.filters, limit_page_length=None, order_by=order_by diff --git a/frappe/core/doctype/data_export/test_data_exporter.py b/frappe/core/doctype/data_export/test_data_exporter.py index 7b7dfc0069..812f65aaad 100644 --- a/frappe/core/doctype/data_export/test_data_exporter.py +++ b/frappe/core/doctype/data_export/test_data_exporter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/data_import/data_import.py b/frappe/core/doctype/data_import/data_import.py index 06282e5831..5ad603e416 100644 --- a/frappe/core/doctype/data_import/data_import.py +++ b/frappe/core/doctype/data_import/data_import.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/data_import/exporter.py b/frappe/core/doctype/data_import/exporter.py index b647bdcb62..8c73391bd0 100644 --- a/frappe/core/doctype/data_import/exporter.py +++ b/frappe/core/doctype/data_import/exporter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE @@ -132,8 +131,7 @@ class Exporter: child_doctype = table_df.options rows = self.add_data_row(child_doctype, child_row.parentfield, child_row, rows, i) - for row in rows: - yield row + yield from rows def add_data_row(self, doctype, parentfield, doc, rows, row_idx): if len(rows) < row_idx + 1: @@ -156,14 +154,14 @@ class Exporter: def get_data_as_docs(self): def format_column_name(df): - return "`tab{0}`.`{1}`".format(df.parent, df.fieldname) + return f"`tab{df.parent}`.`{df.fieldname}`" filters = self.export_filters if self.meta.is_nested_set(): - order_by = "`tab{0}`.`lft` ASC".format(self.doctype) + order_by = f"`tab{self.doctype}`.`lft` ASC" else: - order_by = "`tab{0}`.`creation` DESC".format(self.doctype) + order_by = f"`tab{self.doctype}`.`creation` DESC" parent_fields = [format_column_name(df) for df in self.fields if df.parent == self.doctype] parent_data = frappe.db.get_list( @@ -183,7 +181,7 @@ class Exporter: child_table_df = self.meta.get_field(key) child_table_doctype = child_table_df.options child_fields = ["name", "idx", "parent", "parentfield"] + list( - set([format_column_name(df) for df in self.fields if df.parent == child_table_doctype]) + {format_column_name(df) for df in self.fields if df.parent == child_table_doctype} ) data = frappe.db.get_all( child_table_doctype, @@ -211,16 +209,16 @@ class Exporter: if is_parent: label = _(df.label) else: - label = "{0} ({1})".format(_(df.label), _(df.child_table_df.label)) + label = f"{_(df.label)} ({_(df.child_table_df.label)})" if label in header: # this label is already in the header, # which means two fields with the same label # add the fieldname to avoid clash if is_parent: - label = "{0}".format(df.fieldname) + label = f"{df.fieldname}" else: - label = "{0}.{1}".format(df.child_table_df.fieldname, df.fieldname) + label = f"{df.child_table_df.fieldname}.{df.fieldname}" header.append(label) @@ -253,5 +251,5 @@ class Exporter: def build_xlsx_response(self): build_xlsx_response(self.get_csv_array_for_export(), _(self.doctype)) - def group_children_data_by_parent(self, children_data: typing.Dict[str, list]): + def group_children_data_by_parent(self, children_data: dict[str, list]): return groupby_metric(children_data, key="parent") diff --git a/frappe/core/doctype/data_import/importer.py b/frappe/core/doctype/data_import/importer.py index 06d7588aef..9e741ab590 100644 --- a/frappe/core/doctype/data_import/importer.py +++ b/frappe/core/doctype/data_import/importer.py @@ -150,7 +150,7 @@ class Importer: if self.console: update_progress_bar( - "Importing {0} records".format(total_payload_count), + f"Importing {total_payload_count} records", current_index, total_payload_count, ) @@ -342,7 +342,7 @@ class Importer: row_number = json.loads(log.get("row_indexes"))[0] status = "Success" if log.get("success") else "Failure" message = ( - "Successfully Imported {0}".format(log.get("docname")) + "Successfully Imported {}".format(log.get("docname")) if log.get("success") else log.get("messages") ) @@ -357,19 +357,17 @@ class Importer: if successful_records: print() - print( - "Successfully imported {0} records out of {1}".format(len(successful_records), len(import_log)) - ) + print(f"Successfully imported {len(successful_records)} records out of {len(import_log)}") if failed_records: - print("Failed to import {0} records".format(len(failed_records))) - file_name = "{0}_import_on_{1}.txt".format(self.doctype, frappe.utils.now()) - print("Check {0} for errors".format(os.path.join("sites", file_name))) + print(f"Failed to import {len(failed_records)} records") + file_name = f"{self.doctype}_import_on_{frappe.utils.now()}.txt" + print("Check {} for errors".format(os.path.join("sites", file_name))) text = "" for w in failed_records: - text += "Row Indexes: {0}\n".format(str(w.get("row_indexes", []))) - text += "Messages:\n{0}\n".format("\n".join(w.get("messages", []))) - text += "Traceback:\n{0}\n\n".format(w.get("exception")) + text += "Row Indexes: {}\n".format(str(w.get("row_indexes", []))) + text += "Messages:\n{}\n".format("\n".join(w.get("messages", []))) + text += "Traceback:\n{}\n\n".format(w.get("exception")) with open(file_name, "w") as f: f.write(text) @@ -384,7 +382,7 @@ class Importer: other_warnings.append(w) for row_number, warnings in warnings_by_row.items(): - print("Row {0}".format(row_number)) + print(f"Row {row_number}") for w in warnings: print(w.get("message")) @@ -578,7 +576,7 @@ class ImportFile: extn = os.path.splitext(file_path)[1][1:] file_content = None - with io.open(file_path, mode="rb") as f: + with open(file_path, mode="rb") as f: file_content = f.read() return file_content, extn @@ -991,9 +989,7 @@ class Column: self.warnings.append( { "col": self.column_number, - "message": ( - "The following values do not exist for {}: {}".format(self.df.options, missing_values) - ), + "message": (f"The following values do not exist for {self.df.options}: {missing_values}"), "type": "warning", } ) @@ -1023,8 +1019,8 @@ class Column: { "col": self.column_number, "message": ( - "The following values are invalid: {0}. Values must be" - " one of {1}".format(invalid_values, valid_values) + "The following values are invalid: {}. Values must be" + " one of {}".format(invalid_values, valid_values) ), } ) @@ -1110,9 +1106,9 @@ def build_fields_dict_for_column_matching(parent_doctype): ) else: name_headers = ( - "{0}.name".format(table_df.fieldname), # fieldname - "ID ({0})".format(table_df.label), # label - "{0} ({1})".format(_("ID"), translated_table_label), # translated label + f"{table_df.fieldname}.name", # fieldname + f"ID ({table_df.label})", # label + "{} ({})".format(_("ID"), translated_table_label), # translated label ) name_df.is_child_table_field = True @@ -1164,11 +1160,11 @@ def build_fields_dict_for_column_matching(parent_doctype): for header in ( # fieldname - "{0}.{1}".format(table_df.fieldname, df.fieldname), + f"{table_df.fieldname}.{df.fieldname}", # label - "{0} ({1})".format(label, table_df.label), + f"{label} ({table_df.label})", # translated label - "{0} ({1})".format(translated_label, translated_table_label), + f"{translated_label} ({translated_table_label})", ): out[header] = new_df @@ -1177,8 +1173,8 @@ def build_fields_dict_for_column_matching(parent_doctype): autoname_field = get_autoname_field(parent_doctype) if autoname_field: for header in ( - "ID ({})".format(autoname_field.label), # label - "{0} ({1})".format(_("ID"), _(autoname_field.label)), # translated label + f"ID ({autoname_field.label})", # label + "{} ({})".format(_("ID"), _(autoname_field.label)), # translated label # ID field should also map to the autoname field "ID", _("ID"), diff --git a/frappe/core/doctype/data_import/test_data_import.py b/frappe/core/doctype/data_import/test_data_import.py index fb15b3ad52..253882383c 100644 --- a/frappe/core/doctype/data_import/test_data_import.py +++ b/frappe/core/doctype/data_import/test_data_import.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/data_import/test_exporter.py b/frappe/core/doctype/data_import/test_exporter.py index ed01a2648c..ceeac90e36 100644 --- a/frappe/core/doctype/data_import/test_exporter.py +++ b/frappe/core/doctype/data_import/test_exporter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/data_import/test_importer.py b/frappe/core/doctype/data_import/test_importer.py index 46b3c352ca..2c250a4e87 100644 --- a/frappe/core/doctype/data_import/test_importer.py +++ b/frappe/core/doctype/data_import/test_importer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/deleted_document/deleted_document.py b/frappe/core/doctype/deleted_document/deleted_document.py index f2c98a41b8..14b9bb5c11 100644 --- a/frappe/core/doctype/deleted_document/deleted_document.py +++ b/frappe/core/doctype/deleted_document/deleted_document.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/deleted_document/test_deleted_document.py b/frappe/core/doctype/deleted_document/test_deleted_document.py index 8985298498..f696689664 100644 --- a/frappe/core/doctype/deleted_document/test_deleted_document.py +++ b/frappe/core/doctype/deleted_document/test_deleted_document.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index a965d9c1b2..dbbbbc521a 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -248,7 +248,7 @@ class DocType(Document): self.flags.update_fields_to_fetch_queries = [] - if set(old_fields_to_fetch) != set(df.fieldname for df in new_meta.get_fields_to_fetch()): + if set(old_fields_to_fetch) != {df.fieldname for df in new_meta.get_fields_to_fetch()}: for df in new_meta.get_fields_to_fetch(): if df.fieldname not in old_fields_to_fetch: link_fieldname, source_fieldname = df.fetch_from.split(".", 1) @@ -385,7 +385,7 @@ class DocType(Document): try: frappe.db.updatedb(self.name, Meta(self)) except Exception as e: - print("\n\nThere was an issue while migrating the DocType: {}\n".format(self.name)) + print(f"\n\nThere was an issue while migrating the DocType: {self.name}\n") raise e self.change_modified_of_parent() @@ -552,7 +552,7 @@ class DocType(Document): for fname in ("{}.js", "{}.py", "{}_list.js", "{}_calendar.js", "test_{}.py", "test_{}.js"): fname = os.path.join(new_path, fname.format(frappe.scrub(new))) if os.path.exists(fname): - with open(fname, "r") as f: + with open(fname) as f: code = f.read() with open(fname, "w") as f: if fname.endswith(".js"): @@ -569,7 +569,7 @@ class DocType(Document): f.write(file_content) # updating json file with new name - doctype_json_path = os.path.join(new_path, "{}.json".format(frappe.scrub(new))) + doctype_json_path = os.path.join(new_path, f"{frappe.scrub(new)}.json") current_data = frappe.get_file_json(doctype_json_path) current_data["name"] = new @@ -643,7 +643,7 @@ class DocType(Document): path = get_file_path(self.module, "DocType", self.name) if os.path.exists(path): try: - with open(path, "r") as txtfile: + with open(path) as txtfile: olddoc = json.loads(txtfile.read()) old_field_names = [f["fieldname"] for f in olddoc.get("fields", [])] @@ -652,14 +652,14 @@ class DocType(Document): remaining_field_names = [f.fieldname for f in self.fields] for fieldname in old_field_names: - field_dict = list(filter(lambda d: d["fieldname"] == fieldname, docdict["fields"])) + field_dict = [f for f in docdict["fields"] if f["fieldname"] == fieldname] if field_dict: new_field_dicts.append(field_dict[0]) if fieldname in remaining_field_names: remaining_field_names.remove(fieldname) for fieldname in remaining_field_names: - field_dict = list(filter(lambda d: d["fieldname"] == fieldname, docdict["fields"])) + field_dict = [f for f in docdict["fields"] if f["fieldname"] == fieldname] new_field_dicts.append(field_dict[0]) docdict["fields"] = new_field_dicts @@ -674,14 +674,14 @@ class DocType(Document): remaining_field_names = [f["fieldname"] for f in docdict.get("fields", [])] for fieldname in docdict.get("field_order"): - field_dict = list(filter(lambda d: d["fieldname"] == fieldname, docdict.get("fields", []))) + field_dict = [f for f in docdict.get("fields", []) if f["fieldname"] == fieldname] if field_dict: new_field_dicts.append(field_dict[0]) if fieldname in remaining_field_names: remaining_field_names.remove(fieldname) for fieldname in remaining_field_names: - field_dict = list(filter(lambda d: d["fieldname"] == fieldname, docdict.get("fields", []))) + field_dict = [f for f in docdict.get("fields", []) if f["fieldname"] == fieldname] new_field_dicts.append(field_dict[0]) docdict["fields"] = new_field_dicts @@ -804,7 +804,7 @@ class DocType(Document): {"label": "Old Parent", "fieldtype": "Link", "options": self.name, "fieldname": "old_parent"}, ) - parent_field_label = "Parent {}".format(self.name) + parent_field_label = f"Parent {self.name}" parent_field_name = frappe.scrub(parent_field_label) self.append( "fields", @@ -1417,7 +1417,7 @@ def validate_fields(meta): def check_max_height(docfield): if getattr(docfield, "max_height", None) and (docfield.max_height[-2:] not in ("px", "em")): - frappe.throw("Max for {} height must be in px, em, rem".format(frappe.bold(docfield.fieldname))) + frappe.throw(f"Max for {frappe.bold(docfield.fieldname)} height must be in px, em, rem") def check_no_of_ratings(docfield): if docfield.fieldtype == "Rating": diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 5b0b575201..3a5ca4329f 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -1,10 +1,8 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import random import string import unittest -from typing import Dict, List, Optional from unittest.mock import patch import frappe @@ -187,7 +185,7 @@ class TestDocType(unittest.TestCase): "module": "Core", "custom": 1, "fields": [ - {"fieldname": "{0}_field".format(field_option), "fieldtype": "Data", "options": field_option} + {"fieldname": f"{field_option}_field", "fieldtype": "Data", "options": field_option} ], } ) @@ -711,10 +709,10 @@ class TestDocType(unittest.TestCase): def new_doctype( - name: Optional[str] = None, + name: str | None = None, unique: bool = False, depends_on: str = "", - fields: Optional[List[Dict]] = None, + fields: list[dict] | None = None, **kwargs, ): if not name: diff --git a/frappe/core/doctype/doctype_action/doctype_action.py b/frappe/core/doctype/doctype_action/doctype_action.py index 49cb21f99f..1c5be9ae01 100644 --- a/frappe/core/doctype/doctype_action/doctype_action.py +++ b/frappe/core/doctype/doctype_action/doctype_action.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/doctype_link/doctype_link.py b/frappe/core/doctype/doctype_link/doctype_link.py index f534cd1780..0658b1fb28 100644 --- a/frappe/core/doctype/doctype_link/doctype_link.py +++ b/frappe/core/doctype/doctype_link/doctype_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.py b/frappe/core/doctype/document_naming_rule/document_naming_rule.py index 41aa3d7aff..3fecf26ade 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.py +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/document_naming_rule/test_document_naming_rule.py b/frappe/core/doctype/document_naming_rule/test_document_naming_rule.py index 459b17da8b..cc406ed5cd 100644 --- a/frappe/core/doctype/document_naming_rule/test_document_naming_rule.py +++ b/frappe/core/doctype/document_naming_rule/test_document_naming_rule.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/document_naming_rule_condition/document_naming_rule_condition.py b/frappe/core/doctype/document_naming_rule_condition/document_naming_rule_condition.py index dc45798c34..7ecc0162a5 100644 --- a/frappe/core/doctype/document_naming_rule_condition/document_naming_rule_condition.py +++ b/frappe/core/doctype/document_naming_rule_condition/document_naming_rule_condition.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/document_naming_rule_condition/test_document_naming_rule_condition.py b/frappe/core/doctype/document_naming_rule_condition/test_document_naming_rule_condition.py index d88335758a..68f0677f2c 100644 --- a/frappe/core/doctype/document_naming_rule_condition/test_document_naming_rule_condition.py +++ b/frappe/core/doctype/document_naming_rule_condition/test_document_naming_rule_condition.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/document_naming_settings/document_naming_settings.py b/frappe/core/doctype/document_naming_settings/document_naming_settings.py index 46def88b65..5680b6c823 100644 --- a/frappe/core/doctype/document_naming_settings/document_naming_settings.py +++ b/frappe/core/doctype/document_naming_settings/document_naming_settings.py @@ -1,7 +1,6 @@ # Copyright (c) 2022, Frappe Technologies and contributors # For license information, please see license.txt -from typing import List, Set import frappe from frappe import _ @@ -25,7 +24,7 @@ class DocumentNamingSettings(Document): return {"transactions": transactions, "prefixes": prefixes} - def _get_transactions(self) -> List[str]: + def _get_transactions(self) -> list[str]: readable_doctypes = set(get_doctypes_with_read()) @@ -34,7 +33,7 @@ class DocumentNamingSettings(Document): return sorted(readable_doctypes.intersection(standard + custom)) - def _get_prefixes(self, doctypes) -> List[str]: + def _get_prefixes(self, doctypes) -> list[str]: """Get all prefixes for naming series. - For all templates prefix is evaluated considering today's date @@ -63,7 +62,7 @@ class DocumentNamingSettings(Document): return self._evaluate_and_clean_templates(series_templates) - def _evaluate_and_clean_templates(self, series_templates: Set[str]) -> List[str]: + def _evaluate_and_clean_templates(self, series_templates: set[str]) -> list[str]: evalauted_prefix = set() series = frappe.qb.DocType("Series") @@ -79,7 +78,7 @@ class DocumentNamingSettings(Document): return sorted(evalauted_prefix) - def get_options_list(self, options: str) -> List[str]: + def get_options_list(self, options: str) -> list[str]: return [op.strip() for op in options.split("\n") if op.strip()] @frappe.whitelist() diff --git a/frappe/core/doctype/domain/domain.py b/frappe/core/doctype/domain/domain.py index 897f7ee655..e0b0e80982 100644 --- a/frappe/core/doctype/domain/domain.py +++ b/frappe/core/doctype/domain/domain.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -113,8 +112,8 @@ class Domain(Document): # enable frappe.db.sql( """update `tabPortal Menu Item` set enabled=1 - where route in ({0})""".format( - ", ".join('"{0}"'.format(d) for d in self.data.allow_sidebar_items) + where route in ({})""".format( + ", ".join(f'"{d}"' for d in self.data.allow_sidebar_items) ) ) @@ -125,7 +124,7 @@ class Domain(Document): # enable frappe.db.sql( """update `tabPortal Menu Item` set enabled=0 - where route in ({0})""".format( - ", ".join('"{0}"'.format(d) for d in self.data.remove_sidebar_items) + where route in ({})""".format( + ", ".join(f'"{d}"' for d in self.data.remove_sidebar_items) ) ) diff --git a/frappe/core/doctype/domain/test_domain.py b/frappe/core/doctype/domain/test_domain.py index 623d80a280..32592705b4 100644 --- a/frappe/core/doctype/domain/test_domain.py +++ b/frappe/core/doctype/domain/test_domain.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/domain_settings/domain_settings.py b/frappe/core/doctype/domain_settings/domain_settings.py index ba7f397c51..85b26f53dd 100644 --- a/frappe/core/doctype/domain_settings/domain_settings.py +++ b/frappe/core/doctype/domain_settings/domain_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -32,7 +31,7 @@ class DomainSettings(Document): def restrict_roles_and_modules(self): """Disable all restricted roles and set `restrict_to_domain` property in Module Def""" active_domains = frappe.get_active_domains() - all_domains = list((frappe.get_hooks("domains") or {})) + all_domains = list(frappe.get_hooks("domains") or {}) def remove_role(role): frappe.db.delete("Has Role", {"role": role}) diff --git a/frappe/core/doctype/dynamic_link/dynamic_link.py b/frappe/core/doctype/dynamic_link/dynamic_link.py index e253147167..53eb750b5c 100644 --- a/frappe/core/doctype/dynamic_link/dynamic_link.py +++ b/frappe/core/doctype/dynamic_link/dynamic_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/error_log/error_log.py b/frappe/core/doctype/error_log/error_log.py index 224a5673a7..c7ab98e034 100644 --- a/frappe/core/doctype/error_log/error_log.py +++ b/frappe/core/doctype/error_log/error_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/error_log/test_error_log.py b/frappe/core/doctype/error_log/test_error_log.py index a8511b238e..c7cf26a0cf 100644 --- a/frappe/core/doctype/error_log/test_error_log.py +++ b/frappe/core/doctype/error_log/test_error_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/error_snapshot/error_snapshot.py b/frappe/core/doctype/error_snapshot/error_snapshot.py index 6e13b7a654..6966cf0aca 100644 --- a/frappe/core/doctype/error_snapshot/error_snapshot.py +++ b/frappe/core/doctype/error_snapshot/error_snapshot.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/error_snapshot/test_error_snapshot.py b/frappe/core/doctype/error_snapshot/test_error_snapshot.py index 121fe8a6f9..0c1f861b43 100644 --- a/frappe/core/doctype/error_snapshot/test_error_snapshot.py +++ b/frappe/core/doctype/error_snapshot/test_error_snapshot.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index bb4b441680..7a66d45c73 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -7,7 +7,6 @@ import os import re import shutil import zipfile -from typing import List, Optional, Union from urllib.parse import quote, unquote from PIL import Image, ImageFile, ImageOps @@ -134,7 +133,7 @@ class File(Document): shutil.move(source, target) self.flags.pop("original_path") - def get_name_based_on_parent_folder(self) -> Union[str, None]: + def get_name_based_on_parent_folder(self) -> str | None: if self.folder: return os.path.join(self.folder, self.file_name) @@ -328,7 +327,7 @@ class File(Document): file_path = get_files_path(file_name, is_private=self.is_private) with open(file_path, "rb") as f: self.content_hash = get_content_hash(f.read()) - except IOError: + except OSError: frappe.throw(_("File {0} does not exist").format(file_path)) def make_thumbnail( @@ -347,7 +346,7 @@ class File(Document): image, filename, extn = get_local_image(self.file_url) else: image, filename, extn = get_web_image(self.file_url) - except (HTTPError, SSLError, IOError, TypeError): + except (HTTPError, SSLError, OSError, TypeError): return size = width, height @@ -364,7 +363,7 @@ class File(Document): if set_as_thumbnail: self.db_set("thumbnail_url", thumbnail_url) - except IOError: + except OSError: frappe.msgprint(_("Unable to write file format for {0}").format(path)) return @@ -387,7 +386,7 @@ class File(Document): else: self.delete_file_data_content(only_thumbnail=True) - def unzip(self) -> List["File"]: + def unzip(self) -> list["File"]: """Unzip current file and replace it by its children""" if not self.file_url.endswith(".zip"): frappe.throw(_("{0} is not a zip file").format(self.file_name)) @@ -506,7 +505,7 @@ class File(Document): def save_file( self, - content: Optional[Union[bytes, str]] = None, + content: bytes | str | None = None, decode=False, ignore_existing_file_check=False, overwrite=False, diff --git a/frappe/core/doctype/file/utils.py b/frappe/core/doctype/file/utils.py index 632324c9cf..e59ec2aede 100644 --- a/frappe/core/doctype/file/utils.py +++ b/frappe/core/doctype/file/utils.py @@ -4,7 +4,7 @@ import mimetypes import os import re from io import BytesIO -from typing import TYPE_CHECKING, Optional, Tuple, Union +from typing import TYPE_CHECKING, Optional from urllib.parse import unquote import requests @@ -55,8 +55,8 @@ def setup_folder_path(filename: str, new_parent: str) -> None: def get_extension( filename, - extn: Optional[str] = None, - content: Optional[bytes] = None, + extn: str | None = None, + content: bytes | None = None, response: Optional["Response"] = None, ) -> str: mimetype = None @@ -83,7 +83,7 @@ def get_extension( return extn -def get_local_image(file_url: str) -> Tuple["ImageFile", str, str]: +def get_local_image(file_url: str) -> tuple["ImageFile", str, str]: if file_url.startswith("/private"): file_url_path = (file_url.lstrip("/"),) else: @@ -93,7 +93,7 @@ def get_local_image(file_url: str) -> Tuple["ImageFile", str, str]: try: image = Image.open(file_path) - except IOError: + except OSError: frappe.throw(_("Unable to read file format for {0}").format(file_url)) content = None @@ -102,7 +102,7 @@ def get_local_image(file_url: str) -> Tuple["ImageFile", str, str]: filename, extn = file_url.rsplit(".", 1) except ValueError: # no extn - with open(file_path, "r") as f: + with open(file_path) as f: content = f.read() filename = file_url @@ -113,7 +113,7 @@ def get_local_image(file_url: str) -> Tuple["ImageFile", str, str]: return image, filename, extn -def get_web_image(file_url: str) -> Tuple["ImageFile", str, str]: +def get_web_image(file_url: str) -> tuple["ImageFile", str, str]: # download file_url = frappe.utils.get_url(file_url) r = requests.get(file_url, stream=True) @@ -179,13 +179,13 @@ def remove_file_by_url(file_url: str, doctype: str = None, name: str = None) -> return remove_file(fid=fid) -def get_content_hash(content: Union[bytes, str]) -> str: +def get_content_hash(content: bytes | str) -> str: if isinstance(content, str): content = content.encode() return hashlib.md5(content).hexdigest() # nosec -def generate_file_name(name: str, suffix: Optional[str] = None, is_private: bool = False) -> str: +def generate_file_name(name: str, suffix: str | None = None, is_private: bool = False) -> str: """Generate conflict-free file name. Suffix will be ignored if name available. If the provided suffix doesn't result in an available path, a random suffix will be picked. """ @@ -203,7 +203,7 @@ def generate_file_name(name: str, suffix: Optional[str] = None, is_private: bool return candidate_path -def get_file_name(fname: str, optional_suffix: Optional[str] = None) -> str: +def get_file_name(fname: str, optional_suffix: str | None = None) -> str: # convert to unicode fname = cstr(fname) partial, extn = os.path.splitext(fname) diff --git a/frappe/core/doctype/has_domain/has_domain.py b/frappe/core/doctype/has_domain/has_domain.py index 8ef69ef0c4..0d8257fc33 100644 --- a/frappe/core/doctype/has_domain/has_domain.py +++ b/frappe/core/doctype/has_domain/has_domain.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/has_role/has_role.py b/frappe/core/doctype/has_role/has_role.py index 83cf90aac6..8798adf031 100644 --- a/frappe/core/doctype/has_role/has_role.py +++ b/frappe/core/doctype/has_role/has_role.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/installed_application/installed_application.py b/frappe/core/doctype/installed_application/installed_application.py index 07b6c105af..0a1dab8f2e 100644 --- a/frappe/core/doctype/installed_application/installed_application.py +++ b/frappe/core/doctype/installed_application/installed_application.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/installed_applications/installed_applications.py b/frappe/core/doctype/installed_applications/installed_applications.py index d13118e169..07b20db153 100644 --- a/frappe/core/doctype/installed_applications/installed_applications.py +++ b/frappe/core/doctype/installed_applications/installed_applications.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/installed_applications/test_installed_applications.py b/frappe/core/doctype/installed_applications/test_installed_applications.py index 24d3a9a49a..b67cc4c8c7 100644 --- a/frappe/core/doctype/installed_applications/test_installed_applications.py +++ b/frappe/core/doctype/installed_applications/test_installed_applications.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/language/language.py b/frappe/core/doctype/language/language.py index 948810eb39..efac7b0d77 100644 --- a/frappe/core/doctype/language/language.py +++ b/frappe/core/doctype/language/language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -42,7 +41,7 @@ def export_languages_json(): def sync_languages(): """Sync frappe/geo/languages.json with Language""" - with open(frappe.get_app_path("frappe", "geo", "languages.json"), "r") as f: + with open(frappe.get_app_path("frappe", "geo", "languages.json")) as f: data = json.loads(f.read()) for l in data: @@ -59,7 +58,7 @@ def sync_languages(): def update_language_names(): """Update frappe/geo/languages.json names (for use via patch)""" - with open(frappe.get_app_path("frappe", "geo", "languages.json"), "r") as f: + with open(frappe.get_app_path("frappe", "geo", "languages.json")) as f: data = json.loads(f.read()) for l in data: diff --git a/frappe/core/doctype/language/test_language.py b/frappe/core/doctype/language/test_language.py index 305515c191..1f9c96a5d8 100644 --- a/frappe/core/doctype/language/test_language.py +++ b/frappe/core/doctype/language/test_language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/log_setting_user/log_setting_user.py b/frappe/core/doctype/log_setting_user/log_setting_user.py index cf66da31b1..830d29e3be 100644 --- a/frappe/core/doctype/log_setting_user/log_setting_user.py +++ b/frappe/core/doctype/log_setting_user/log_setting_user.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/log_setting_user/test_log_setting_user.py b/frappe/core/doctype/log_setting_user/test_log_setting_user.py index dc70677079..9ea56e8ec4 100644 --- a/frappe/core/doctype/log_setting_user/test_log_setting_user.py +++ b/frappe/core/doctype/log_setting_user/test_log_setting_user.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/log_settings/log_settings.py b/frappe/core/doctype/log_settings/log_settings.py index 1a7ce532cd..8009324e70 100644 --- a/frappe/core/doctype/log_settings/log_settings.py +++ b/frappe/core/doctype/log_settings/log_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/module_def/module_def.py b/frappe/core/doctype/module_def/module_def.py index 8f80ffd4ee..c9dac11b69 100644 --- a/frappe/core/doctype/module_def/module_def.py +++ b/frappe/core/doctype/module_def/module_def.py @@ -29,7 +29,7 @@ class ModuleDef(Document): """Adds to `[app]/modules.txt`""" modules = None if not frappe.local.module_app.get(frappe.scrub(self.name)): - with open(frappe.get_app_path(self.app_name, "modules.txt"), "r") as f: + with open(frappe.get_app_path(self.app_name, "modules.txt")) as f: content = f.read() if not self.name in content.splitlines(): modules = list(filter(None, content.splitlines())) @@ -50,7 +50,7 @@ class ModuleDef(Document): modules = None if frappe.local.module_app.get(frappe.scrub(self.name)): - with open(frappe.get_app_path(self.app_name, "modules.txt"), "r") as f: + with open(frappe.get_app_path(self.app_name, "modules.txt")) as f: content = f.read() if self.name in content.splitlines(): modules = list(filter(None, content.splitlines())) diff --git a/frappe/core/doctype/module_def/test_module_def.py b/frappe/core/doctype/module_def/test_module_def.py index 3a6da6d854..914ba07949 100644 --- a/frappe/core/doctype/module_def/test_module_def.py +++ b/frappe/core/doctype/module_def/test_module_def.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/module_profile/module_profile.py b/frappe/core/doctype/module_profile/module_profile.py index 7c5f896ba8..46c09827f3 100644 --- a/frappe/core/doctype/module_profile/module_profile.py +++ b/frappe/core/doctype/module_profile/module_profile.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/module_profile/test_module_profile.py b/frappe/core/doctype/module_profile/test_module_profile.py index e15a70d93f..099d1371fb 100644 --- a/frappe/core/doctype/module_profile/test_module_profile.py +++ b/frappe/core/doctype/module_profile/test_module_profile.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/navbar_item/navbar_item.py b/frappe/core/doctype/navbar_item/navbar_item.py index 27aa339c93..60be154e75 100644 --- a/frappe/core/doctype/navbar_item/navbar_item.py +++ b/frappe/core/doctype/navbar_item/navbar_item.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/navbar_item/test_navbar_item.py b/frappe/core/doctype/navbar_item/test_navbar_item.py index 913e84704b..7eeb4f642b 100644 --- a/frappe/core/doctype/navbar_item/test_navbar_item.py +++ b/frappe/core/doctype/navbar_item/test_navbar_item.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py index 6243107d63..1eba0f8fa7 100644 --- a/frappe/core/doctype/navbar_settings/navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/navbar_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/navbar_settings/test_navbar_settings.py b/frappe/core/doctype/navbar_settings/test_navbar_settings.py index f63e361e8b..76fb3d298a 100644 --- a/frappe/core/doctype/navbar_settings/test_navbar_settings.py +++ b/frappe/core/doctype/navbar_settings/test_navbar_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/package/package.py b/frappe/core/doctype/package/package.py index a32f1bc534..c1cb482832 100644 --- a/frappe/core/doctype/package/package.py +++ b/frappe/core/doctype/package/package.py @@ -15,7 +15,5 @@ class Package(Document): @frappe.whitelist() def get_license_text(license_type): - with open( - os.path.join(os.path.dirname(__file__), "licenses", license_type + ".md"), "r" - ) as textfile: + with open(os.path.join(os.path.dirname(__file__), "licenses", license_type + ".md")) as textfile: return textfile.read() diff --git a/frappe/core/doctype/package_import/package_import.py b/frappe/core/doctype/package_import/package_import.py index 43a985af9b..19762eae4a 100644 --- a/frappe/core/doctype/package_import/package_import.py +++ b/frappe/core/doctype/package_import/package_import.py @@ -44,7 +44,7 @@ class PackageImport(Document): package_path = frappe.get_site_path("packages", package_name) # import Package - with open(os.path.join(package_path, package_name + ".json"), "r") as packagefile: + with open(os.path.join(package_path, package_name + ".json")) as packagefile: doc_dict = json.loads(packagefile.read()) frappe.flags.package = import_doc(doc_dict) @@ -60,6 +60,6 @@ class PackageImport(Document): # import files for file in files: import_file_by_path(file, force=self.force, ignore_version=True) - log.append("Imported {}".format(file)) + log.append(f"Imported {file}") self.log = "\n".join(log) diff --git a/frappe/core/doctype/package_release/package_release.py b/frappe/core/doctype/package_release/package_release.py index 05277dcf2e..58fdc2ab86 100644 --- a/frappe/core/doctype/package_release/package_release.py +++ b/frappe/core/doctype/package_release/package_release.py @@ -87,7 +87,7 @@ class PackageRelease(Document): def make_tarfile(self, package): # make tarfile - filename = "{}.tar.gz".format(self.name) + filename = f"{self.name}.tar.gz" subprocess.check_output( ["tar", "czf", filename, package.package_name], cwd=frappe.get_site_path("packages") ) diff --git a/frappe/core/doctype/page/page.py b/frappe/core/doctype/page/page.py index 7185a25e01..8210875b3a 100644 --- a/frappe/core/doctype/page/page.py +++ b/frappe/core/doctype/page/page.py @@ -79,7 +79,7 @@ class Page(Document): ) def as_dict(self, no_nulls=False): - d = super(Page, self).as_dict(no_nulls=no_nulls) + d = super().as_dict(no_nulls=no_nulls) for key in ("script", "style", "content"): d[key] = self.get(key) return d @@ -120,20 +120,20 @@ class Page(Document): # script fpath = os.path.join(path, page_name + ".js") if os.path.exists(fpath): - with open(fpath, "r") as f: + with open(fpath) as f: self.script = render_include(f.read()) self.script += f"\n\n//# sourceURL={page_name}.js" # css fpath = os.path.join(path, page_name + ".css") if os.path.exists(fpath): - with open(fpath, "r") as f: + with open(fpath) as f: self.style = safe_decode(f.read()) # html as js template for fname in os.listdir(path): if fname.endswith(".html"): - with open(os.path.join(path, fname), "r") as f: + with open(os.path.join(path, fname)) as f: template = f.read() if "" in template: context = frappe._dict({}) diff --git a/frappe/core/doctype/patch_log/test_patch_log.py b/frappe/core/doctype/patch_log/test_patch_log.py index 54cdc6416a..0c8a2ae4d4 100644 --- a/frappe/core/doctype/patch_log/test_patch_log.py +++ b/frappe/core/doctype/patch_log/test_patch_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/payment_gateway/payment_gateway.py b/frappe/core/doctype/payment_gateway/payment_gateway.py index 7eb4c5481d..74306ae4ad 100644 --- a/frappe/core/doctype/payment_gateway/payment_gateway.py +++ b/frappe/core/doctype/payment_gateway/payment_gateway.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/payment_gateway/test_payment_gateway.py b/frappe/core/doctype/payment_gateway/test_payment_gateway.py index 71766561b3..6900e79434 100644 --- a/frappe/core/doctype/payment_gateway/test_payment_gateway.py +++ b/frappe/core/doctype/payment_gateway/test_payment_gateway.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py index e35ec43565..0ff4ce3070 100644 --- a/frappe/core/doctype/prepared_report/prepared_report.py +++ b/frappe/core/doctype/prepared_report/prepared_report.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -103,7 +102,7 @@ def delete_prepared_reports(reports): def create_json_gz_file(data, dt, dn): # Storing data in CSV file causes information loss # Reports like P&L Statement were completely unsuable because of this - json_filename = "{0}.json.gz".format( + json_filename = "{}.json.gz".format( frappe.utils.data.format_datetime(frappe.utils.now(), "Y-m-d-H:M") ) encoded_content = frappe.safe_encode(frappe.as_json(data)) diff --git a/frappe/core/doctype/prepared_report/test_prepared_report.py b/frappe/core/doctype/prepared_report/test_prepared_report.py index 86793cb802..6d0c809a01 100644 --- a/frappe/core/doctype/prepared_report/test_prepared_report.py +++ b/frappe/core/doctype/prepared_report/test_prepared_report.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import json diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py index efb45f41c8..7fe3cadf9c 100644 --- a/frappe/core/doctype/report/report.py +++ b/frappe/core/doctype/report/report.py @@ -243,7 +243,7 @@ class Report(Document): @staticmethod def _format(parts): # sort by is saved as DocType.fieldname, covert it to sql - return "`tab{0}`.`{1}`".format(*parts) + return "`tab{}`.`{}`".format(*parts) def get_standard_report_columns(self, params): if params.get("fields"): @@ -365,9 +365,7 @@ def get_group_by_field(args, doctype): if args["aggregate_function"] == "count": group_by_field = "count(*) as _aggregate_column" else: - group_by_field = "{0}({1}) as _aggregate_column".format( - args.aggregate_function, args.aggregate_on - ) + group_by_field = f"{args.aggregate_function}({args.aggregate_on}) as _aggregate_column" return group_by_field diff --git a/frappe/core/doctype/report/test_report.py b/frappe/core/doctype/report/test_report.py index bbae616e93..0e1ed80eda 100644 --- a/frappe/core/doctype/report/test_report.py +++ b/frappe/core/doctype/report/test_report.py @@ -22,7 +22,7 @@ class TestReport(FrappeTestCase): if frappe.db.exists("Report", "User Activity Report"): frappe.delete_doc("Report", "User Activity Report") - with open(os.path.join(os.path.dirname(__file__), "user_activity_report.json"), "r") as f: + with open(os.path.join(os.path.dirname(__file__), "user_activity_report.json")) as f: frappe.get_doc(json.loads(f.read())).insert() report = frappe.get_doc("Report", "User Activity Report") @@ -223,7 +223,7 @@ class TestReport(FrappeTestCase): if frappe.db.exists("Report", "User Activity Report Without Sort"): frappe.delete_doc("Report", "User Activity Report Without Sort") with open( - os.path.join(os.path.dirname(__file__), "user_activity_report_without_sort.json"), "r" + os.path.join(os.path.dirname(__file__), "user_activity_report_without_sort.json") ) as f: frappe.get_doc(json.loads(f.read())).insert() diff --git a/frappe/core/doctype/report_column/report_column.py b/frappe/core/doctype/report_column/report_column.py index c0984a5ca8..0d6045d121 100644 --- a/frappe/core/doctype/report_column/report_column.py +++ b/frappe/core/doctype/report_column/report_column.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/report_filter/report_filter.py b/frappe/core/doctype/report_filter/report_filter.py index e35d7064d2..f3a9607e20 100644 --- a/frappe/core/doctype/report_filter/report_filter.py +++ b/frappe/core/doctype/report_filter/report_filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/role/role.py b/frappe/core/doctype/role/role.py index 2119f3caa1..97a0e9b581 100644 --- a/frappe/core/doctype/role/role.py +++ b/frappe/core/doctype/role/role.py @@ -99,7 +99,7 @@ def get_users(role): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs def role_query(doctype, txt, searchfield, start, page_len, filters): - report_filters = [["Role", "name", "like", "%{}%".format(txt)], ["Role", "is_custom", "=", 0]] + report_filters = [["Role", "name", "like", f"%{txt}%"], ["Role", "is_custom", "=", 0]] if filters and isinstance(filters, list): report_filters.extend(filters) diff --git a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py index d89131b0d7..bd61995ba3 100644 --- a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py +++ b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/role_profile/role_profile.py b/frappe/core/doctype/role_profile/role_profile.py index ab4660d7c9..a8abd6d1c1 100644 --- a/frappe/core/doctype/role_profile/role_profile.py +++ b/frappe/core/doctype/role_profile/role_profile.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/role_profile/test_role_profile.py b/frappe/core/doctype/role_profile/test_role_profile.py index 19239a81cd..726a5fc83e 100644 --- a/frappe/core/doctype/role_profile/test_role_profile.py +++ b/frappe/core/doctype/role_profile/test_role_profile.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/scheduled_job_log/scheduled_job_log.py b/frappe/core/doctype/scheduled_job_log/scheduled_job_log.py index 68541a36a0..01fa837af0 100644 --- a/frappe/core/doctype/scheduled_job_log/scheduled_job_log.py +++ b/frappe/core/doctype/scheduled_job_log/scheduled_job_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/scheduled_job_log/test_scheduled_job_log.py b/frappe/core/doctype/scheduled_job_log/test_scheduled_job_log.py index 3c99bb5cb8..11d60e35d8 100644 --- a/frappe/core/doctype/scheduled_job_log/test_scheduled_job_log.py +++ b/frappe/core/doctype/scheduled_job_log/test_scheduled_job_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py index 673805ae8b..1c178fcee2 100644 --- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py +++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py @@ -3,8 +3,8 @@ import json from datetime import datetime -from typing import Dict, List +import click from croniter import croniter import frappe @@ -138,14 +138,14 @@ def run_scheduled_job(job_type: str): print(frappe.get_traceback()) -def sync_jobs(hooks: Dict = None): +def sync_jobs(hooks: dict = None): frappe.reload_doc("core", "doctype", "scheduled_job_type") scheduler_events = hooks or frappe.get_hooks("scheduler_events") all_events = insert_events(scheduler_events) clear_events(all_events) -def insert_events(scheduler_events: Dict) -> List: +def insert_events(scheduler_events: dict) -> list: cron_jobs, event_jobs = [], [] for event_type in scheduler_events: events = scheduler_events.get(event_type) @@ -157,7 +157,7 @@ def insert_events(scheduler_events: Dict) -> List: return cron_jobs + event_jobs -def insert_cron_jobs(events: Dict) -> List: +def insert_cron_jobs(events: dict) -> list: cron_jobs = [] for cron_format in events: for event in events.get(cron_format): @@ -166,7 +166,7 @@ def insert_cron_jobs(events: Dict) -> List: return cron_jobs -def insert_event_jobs(events: List, event_type: str) -> List: +def insert_event_jobs(events: list, event_type: str) -> list: event_jobs = [] for event in events: event_jobs.append(event) @@ -177,6 +177,12 @@ def insert_event_jobs(events: List, event_type: str) -> List: def insert_single_event(frequency: str, event: str, cron_format: str = None): cron_expr = {"cron_format": cron_format} if cron_format else {} + + try: + frappe.get_attr(event) + except Exception as e: + click.secho(f"{event} is not a valid method: {e}", fg="yellow") + doc = frappe.get_doc( { "doctype": "Scheduled Job Type", @@ -199,7 +205,7 @@ def insert_single_event(frequency: str, event: str, cron_format: str = None): doc.insert() -def clear_events(all_events: List): +def clear_events(all_events: list): for event in frappe.get_all("Scheduled Job Type", fields=["name", "method", "server_script"]): is_server_script = event.server_script is_defined_in_hooks = event.method in all_events diff --git a/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py index 3e63985692..5448bda91f 100644 --- a/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py +++ b/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py index 5fd59e1014..fda5ca8591 100644 --- a/frappe/core/doctype/server_script/server_script.py +++ b/frappe/core/doctype/server_script/server_script.py @@ -1,9 +1,7 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE from types import FunctionType, MethodType, ModuleType -from typing import Dict, List import frappe from frappe import _ @@ -31,7 +29,7 @@ class ServerScript(Document): return {"script": "py"} @property - def scheduled_jobs(self) -> List[Dict[str, str]]: + def scheduled_jobs(self) -> list[dict[str, str]]: return frappe.get_all( "Scheduled Job Type", filters={"server_script": self.name}, @@ -69,7 +67,7 @@ class ServerScript(Document): except Exception as e: frappe.msgprint(str(e), title=_("Compilation warning")) - def execute_method(self) -> Dict: + def execute_method(self) -> dict: """Specific to API endpoint Server Scripts Raises: @@ -110,7 +108,7 @@ class ServerScript(Document): safe_exec(self.script) - def get_permission_query_conditions(self, user: str) -> List[str]: + def get_permission_query_conditions(self, user: str) -> list[str]: """Specific to Permission Query Server Scripts Args: diff --git a/frappe/core/doctype/server_script/test_server_script.py b/frappe/core/doctype/server_script/test_server_script.py index fd600b8205..4c1c12b7f2 100644 --- a/frappe/core/doctype/server_script/test_server_script.py +++ b/frappe/core/doctype/server_script/test_server_script.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/session_default/session_default.py b/frappe/core/doctype/session_default/session_default.py index df261f4a39..3fada1b5e0 100644 --- a/frappe/core/doctype/session_default/session_default.py +++ b/frappe/core/doctype/session_default/session_default.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/session_default_settings/session_default_settings.py b/frappe/core/doctype/session_default_settings/session_default_settings.py index 4ac9b61553..2b0d731920 100644 --- a/frappe/core/doctype/session_default_settings/session_default_settings.py +++ b/frappe/core/doctype/session_default_settings/session_default_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/session_default_settings/test_session_default_settings.py b/frappe/core/doctype/session_default_settings/test_session_default_settings.py index f763f90a1d..aa60085ce9 100644 --- a/frappe/core/doctype/session_default_settings/test_session_default_settings.py +++ b/frappe/core/doctype/session_default_settings/test_session_default_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/sms_parameter/__init__.py b/frappe/core/doctype/sms_parameter/__init__.py index 8b13789179..e69de29bb2 100755 --- a/frappe/core/doctype/sms_parameter/__init__.py +++ b/frappe/core/doctype/sms_parameter/__init__.py @@ -1 +0,0 @@ - diff --git a/frappe/core/doctype/sms_settings/__init__.py b/frappe/core/doctype/sms_settings/__init__.py index 8b13789179..e69de29bb2 100755 --- a/frappe/core/doctype/sms_settings/__init__.py +++ b/frappe/core/doctype/sms_settings/__init__.py @@ -1 +0,0 @@ - diff --git a/frappe/core/doctype/sms_settings/sms_settings.py b/frappe/core/doctype/sms_settings/sms_settings.py index e1da200ee5..686890514a 100644 --- a/frappe/core/doctype/sms_settings/sms_settings.py +++ b/frappe/core/doctype/sms_settings/sms_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/sms_settings/test_sms_settings.py b/frappe/core/doctype/sms_settings/test_sms_settings.py index da1b807594..61be20ff66 100644 --- a/frappe/core/doctype/sms_settings/test_sms_settings.py +++ b/frappe/core/doctype/sms_settings/test_sms_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/success_action/success_action.py b/frappe/core/doctype/success_action/success_action.py index 95a81ee0fb..e3db646a2e 100644 --- a/frappe/core/doctype/success_action/success_action.py +++ b/frappe/core/doctype/success_action/success_action.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/system_settings/test_system_settings.py b/frappe/core/doctype/system_settings/test_system_settings.py index 410762b4e7..b126976eeb 100644 --- a/frappe/core/doctype/system_settings/test_system_settings.py +++ b/frappe/core/doctype/system_settings/test_system_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/test/test.py b/frappe/core/doctype/test/test.py index 8f3cf7111d..664d06ac84 100644 --- a/frappe/core/doctype/test/test.py +++ b/frappe/core/doctype/test/test.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -15,7 +14,7 @@ class test(Document): json.dump(d, read_file) def load_from_db(self): - with open("data_file.json", "r") as read_file: + with open("data_file.json") as read_file: d = json.load(read_file) super(Document, self).__init__(d) @@ -25,20 +24,20 @@ class test(Document): json.dump(d, read_file) def get_list(self, args): - with open("data_file.json", "r") as read_file: + with open("data_file.json") as read_file: return [json.load(read_file)] def get_value(self, fields, filters, **kwargs): # return [] - with open("data_file.json", "r") as read_file: + with open("data_file.json") as read_file: return [json.load(read_file)] def get_count(self, args): # return [] - with open("data_file.json", "r") as read_file: + with open("data_file.json") as read_file: return [json.load(read_file)] def get_stats(self, args): # return [] - with open("data_file.json", "r") as read_file: + with open("data_file.json") as read_file: return [json.load(read_file)] diff --git a/frappe/core/doctype/test/test_test.py b/frappe/core/doctype/test/test_test.py index e4ee3de5dd..6080c200c1 100644 --- a/frappe/core/doctype/test/test_test.py +++ b/frappe/core/doctype/test/test_test.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/transaction_log/test_transaction_log.py b/frappe/core/doctype/transaction_log/test_transaction_log.py index a4bb066eea..8b179f8d85 100644 --- a/frappe/core/doctype/transaction_log/test_transaction_log.py +++ b/frappe/core/doctype/transaction_log/test_transaction_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import hashlib diff --git a/frappe/core/doctype/translation/test_translation.py b/frappe/core/doctype/translation/test_translation.py index df5ae3767a..c9f4e85086 100644 --- a/frappe/core/doctype/translation/test_translation.py +++ b/frappe/core/doctype/translation/test_translation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/translation/translation.json b/frappe/core/doctype/translation/translation.json index 560f3b2ce2..68b83ed5d9 100644 --- a/frappe/core/doctype/translation/translation.json +++ b/frappe/core/doctype/translation/translation.json @@ -1,6 +1,4 @@ { - "_comments": "[]", - "_liked_by": "[]", "actions": [], "allow_import": 1, "autoname": "hash", @@ -26,6 +24,7 @@ "fieldtype": "Link", "label": "Language", "options": "Language", + "reqd": 1, "search_index": 1 }, { @@ -72,20 +71,23 @@ "description": "If your data is in HTML, please copy paste the exact HTML code with the tags.", "fieldname": "source_text", "fieldtype": "Code", - "label": "Source Text" + "label": "Source Text", + "reqd": 1 }, { "fieldname": "translated_text", "fieldtype": "Code", "in_list_view": 1, - "label": "Translated Text" + "label": "Translated Text", + "reqd": 1 } ], "links": [], - "modified": "2021-12-31 10:19:52.541055", + "modified": "2022-07-04 06:53:54.997004", "modified_by": "Administrator", "module": "Core", "name": "Translation", + "naming_rule": "Random", "owner": "Administrator", "permissions": [ { @@ -103,6 +105,7 @@ ], "sort_field": "modified", "sort_order": "DESC", + "states": [], "title_field": "source_text", "track_changes": 1 } \ No newline at end of file diff --git a/frappe/core/doctype/translation/translation.py b/frappe/core/doctype/translation/translation.py index 90ea4d1523..b08198eb13 100644 --- a/frappe/core/doctype/translation/translation.py +++ b/frappe/core/doctype/translation/translation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index cfb2f4d871..bc5c20eb92 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -489,7 +489,7 @@ class User(Document): self.save() def remove_roles(self, *roles): - existing_roles = dict((d.role, d) for d in self.get("roles")) + existing_roles = {d.role: d for d in self.get("roles")} for role in roles: if role in existing_roles: self.get("roles").remove(existing_roles[role]) @@ -498,7 +498,7 @@ class User(Document): def remove_all_roles_for_guest(self): if self.name == "Guest": - self.set("roles", list(set(d for d in self.get("roles") if d.role == "Guest"))) + self.set("roles", list({d for d in self.get("roles") if d.role == "Guest"})) def remove_disabled_roles(self): disabled_roles = [d.name for d in frappe.get_all("Role", filters={"disabled": 1})] @@ -557,7 +557,7 @@ class User(Document): if not username: # @firstname_last_name username = _check_suggestion( - frappe.scrub("{0} {1}".format(self.first_name, self.last_name or "")) + frappe.scrub("{} {}".format(self.first_name, self.last_name or "")) ) if username: @@ -918,7 +918,7 @@ def user_query(doctype, txt, searchfield, start, page_len, filters): user_type_condition = "" filters.pop("ignore_user_type") - txt = "%{}%".format(txt) + txt = f"%{txt}%" return frappe.db.sql( """SELECT `name`, CONCAT_WS(' ', first_name, middle_name, last_name) FROM `tabUser` @@ -970,7 +970,7 @@ def get_system_users(exclude_users=None, limit=None): limit_cond = "" if limit: - limit_cond = "limit {0}".format(limit) + limit_cond = f"limit {limit}" exclude_users += list(STANDARD_USERS) @@ -1036,7 +1036,7 @@ def notify_admin_access_to_system_manager(login_manager=None): ): site = '{0}'.format(frappe.local.request.host_url) - date_and_time = "{0}".format(format_datetime(now_datetime(), format_string="medium")) + date_and_time = "{}".format(format_datetime(now_datetime(), format_string="medium")) ip_address = frappe.local.request_ip access_message = _("Administrator accessed {0} on {1} via IP Address {2}.").format( diff --git a/frappe/core/doctype/user_document_type/user_document_type.py b/frappe/core/doctype/user_document_type/user_document_type.py index 1e7eab4bd4..731acf582b 100644 --- a/frappe/core/doctype/user_document_type/user_document_type.py +++ b/frappe/core/doctype/user_document_type/user_document_type.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/user_email/user_email.py b/frappe/core/doctype/user_email/user_email.py index 21167ad25d..ebca480f47 100644 --- a/frappe/core/doctype/user_email/user_email.py +++ b/frappe/core/doctype/user_email/user_email.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/user_group/test_user_group.py b/frappe/core/doctype/user_group/test_user_group.py index 546d4fd54c..368f4eaef2 100644 --- a/frappe/core/doctype/user_group/test_user_group.py +++ b/frappe/core/doctype/user_group/test_user_group.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/user_group/user_group.py b/frappe/core/doctype/user_group/user_group.py index a59117426f..812f230f7a 100644 --- a/frappe/core/doctype/user_group/user_group.py +++ b/frappe/core/doctype/user_group/user_group.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/user_group_member/test_user_group_member.py b/frappe/core/doctype/user_group_member/test_user_group_member.py index f1bdc41cff..5d709d0bec 100644 --- a/frappe/core/doctype/user_group_member/test_user_group_member.py +++ b/frappe/core/doctype/user_group_member/test_user_group_member.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/core/doctype/user_group_member/user_group_member.py b/frappe/core/doctype/user_group_member/user_group_member.py index 6b948d797f..e9722a07ad 100644 --- a/frappe/core/doctype/user_group_member/user_group_member.py +++ b/frappe/core/doctype/user_group_member/user_group_member.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/user_select_document_type/user_select_document_type.py b/frappe/core/doctype/user_select_document_type/user_select_document_type.py index 07b8123a13..9cf2e4856d 100644 --- a/frappe/core/doctype/user_select_document_type/user_select_document_type.py +++ b/frappe/core/doctype/user_select_document_type/user_select_document_type.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/user_social_login/user_social_login.py b/frappe/core/doctype/user_social_login/user_social_login.py index d12b5823d1..4cf3f720cd 100644 --- a/frappe/core/doctype/user_social_login/user_social_login.py +++ b/frappe/core/doctype/user_social_login/user_social_login.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/user_type/test_user_type.py b/frappe/core/doctype/user_type/test_user_type.py index 53999ed3df..235881517a 100644 --- a/frappe/core/doctype/user_type/test_user_type.py +++ b/frappe/core/doctype/user_type/test_user_type.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/user_type/user_type.py b/frappe/core/doctype/user_type/user_type.py index 7efb66f569..369e70bf56 100644 --- a/frappe/core/doctype/user_type/user_type.py +++ b/frappe/core/doctype/user_type/user_type.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -211,7 +210,7 @@ def get_user_linked_doctypes(doctype, txt, searchfield, start, page_len, filters ["DocType", "issingle", "=", 0], ["DocType", "module", "not in", modules], ["DocType", "read_only", "=", 0], - ["DocType", "name", "like", "%{0}%".format(txt)], + ["DocType", "name", "like", f"%{txt}%"], ] doctypes = frappe.get_all( @@ -225,7 +224,7 @@ def get_user_linked_doctypes(doctype, txt, searchfield, start, page_len, filters ) custom_dt_filters = [ - ["Custom Field", "dt", "like", "%{0}%".format(txt)], + ["Custom Field", "dt", "like", f"%{txt}%"], ["Custom Field", "options", "=", "User"], ["Custom Field", "fieldtype", "=", "Link"], ] diff --git a/frappe/core/doctype/user_type_module/user_type_module.py b/frappe/core/doctype/user_type_module/user_type_module.py index 83662bfcaf..1dc7c849e8 100644 --- a/frappe/core/doctype/user_type_module/user_type_module.py +++ b/frappe/core/doctype/user_type_module/user_type_module.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/doctype/version/version.py b/frappe/core/doctype/version/version.py index fa6ba0a9cf..99eeb8c2b0 100644 --- a/frappe/core/doctype/version/version.py +++ b/frappe/core/doctype/version/version.py @@ -2,7 +2,6 @@ # License: MIT. See LICENSE import json -from typing import Optional import frappe from frappe.model import no_value_fields, table_fields @@ -10,7 +9,7 @@ from frappe.model.document import Document class Version(Document): - def update_version_info(self, old: Optional[Document], new: Document) -> bool: + def update_version_info(self, old: Document | None, new: Document) -> bool: """Update changed info and return true if change contains useful data.""" if not old: # Check if doc has some information about creation source like data import diff --git a/frappe/core/doctype/view_log/test_view_log.py b/frappe/core/doctype/view_log/test_view_log.py index 04a17cc526..5a88269028 100644 --- a/frappe/core/doctype/view_log/test_view_log.py +++ b/frappe/core/doctype/view_log/test_view_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/core/doctype/view_log/view_log.py b/frappe/core/doctype/view_log/view_log.py index 6156fb74df..8383af818e 100644 --- a/frappe/core/doctype/view_log/view_log.py +++ b/frappe/core/doctype/view_log/view_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/core/page/background_jobs/background_jobs.py b/frappe/core/page/background_jobs/background_jobs.py index 8c3c8ff41e..8ef15b65eb 100644 --- a/frappe/core/page/background_jobs/background_jobs.py +++ b/frappe/core/page/background_jobs/background_jobs.py @@ -1,7 +1,7 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE -from typing import TYPE_CHECKING, Dict, List +from typing import TYPE_CHECKING import frappe from frappe.utils import convert_utc_to_user_timezone @@ -15,7 +15,7 @@ JOB_COLORS = {"queued": "orange", "failed": "red", "started": "blue", "finished" @frappe.whitelist() -def get_info(view=None, queue_timeout=None, job_status=None) -> List[Dict]: +def get_info(view=None, queue_timeout=None, job_status=None) -> list[dict]: jobs = [] def add_job(job: "Job", queue: str) -> None: diff --git a/frappe/core/page/permission_manager/permission_manager.py b/frappe/core/page/permission_manager/permission_manager.py index e2d08488c0..46c9e0aca2 100644 --- a/frappe/core/page/permission_manager/permission_manager.py +++ b/frappe/core/page/permission_manager/permission_manager.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE -from typing import Optional import frappe import frappe.defaults @@ -71,7 +70,7 @@ def get_roles_and_doctypes(): @frappe.whitelist() -def get_permissions(doctype: Optional[str] = None, role: Optional[str] = None): +def get_permissions(doctype: str | None = None, role: str | None = None): frappe.only_for("System Manager") if role: 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 6d7f394beb..362cc6b105 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 @@ -37,12 +37,12 @@ def validate(user, doctype): def get_columns_and_fields(doctype): - columns = ["Name:Link/{}:200".format(doctype)] + columns = [f"Name:Link/{doctype}:200"] fields = ["`name`"] for df in frappe.get_meta(doctype).fields: if df.in_list_view and df.fieldtype in data_fieldtypes: - fields.append("`{0}`".format(df.fieldname)) - fieldtype = "Link/{}".format(df.options) if df.fieldtype == "Link" else df.fieldtype + 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 diff --git a/frappe/custom/doctype/client_script/test_client_script.py b/frappe/custom/doctype/client_script/test_client_script.py index 7497ab7780..c93df04c98 100644 --- a/frappe/custom/doctype/client_script/test_client_script.py +++ b/frappe/custom/doctype/client_script/test_client_script.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/custom/doctype/custom_field/test_custom_field.py b/frappe/custom/doctype/custom_field/test_custom_field.py index 519ea7f2b4..34223315c5 100644 --- a/frappe/custom/doctype/custom_field/test_custom_field.py +++ b/frappe/custom/doctype/custom_field/test_custom_field.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index 20c3a7c025..4923bfc525 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -330,7 +330,7 @@ class CustomizeForm(Document): We need to maintain the order of the link/actions if the user has shuffled them. So we create a new property (ex `links_order`) to keep a list of items. """ - property_name = "{}_order".format(fieldname) + property_name = f"{fieldname}_order" if has_custom: # save the order of the actions and links self.make_property_setter( diff --git a/frappe/custom/doctype/doctype_layout/doctype_layout.py b/frappe/custom/doctype/doctype_layout/doctype_layout.py index f5d37d6f60..ea8e9acc99 100644 --- a/frappe/custom/doctype/doctype_layout/doctype_layout.py +++ b/frappe/custom/doctype/doctype_layout/doctype_layout.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/custom/doctype/doctype_layout/test_doctype_layout.py b/frappe/custom/doctype/doctype_layout/test_doctype_layout.py index 1373b4a53a..0e64a9e727 100644 --- a/frappe/custom/doctype/doctype_layout/test_doctype_layout.py +++ b/frappe/custom/doctype/doctype_layout/test_doctype_layout.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/custom/doctype/doctype_layout_field/doctype_layout_field.py b/frappe/custom/doctype/doctype_layout_field/doctype_layout_field.py index 66fc111d32..f2b8c2b40b 100644 --- a/frappe/custom/doctype/doctype_layout_field/doctype_layout_field.py +++ b/frappe/custom/doctype/doctype_layout_field/doctype_layout_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/custom/doctype/property_setter/test_property_setter.py b/frappe/custom/doctype/property_setter/test_property_setter.py index a1bbc69235..1fa2d2cefb 100644 --- a/frappe/custom/doctype/property_setter/test_property_setter.py +++ b/frappe/custom/doctype/property_setter/test_property_setter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/custom/doctype/test_rename_new/test_rename_new.py b/frappe/custom/doctype/test_rename_new/test_rename_new.py index e79cb60bbe..ed89d1fad1 100644 --- a/frappe/custom/doctype/test_rename_new/test_rename_new.py +++ b/frappe/custom/doctype/test_rename_new/test_rename_new.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/custom/doctype/test_rename_new/test_test_rename_new.py b/frappe/custom/doctype/test_rename_new/test_test_rename_new.py index 513a9286a3..f1ccf42ede 100644 --- a/frappe/custom/doctype/test_rename_new/test_test_rename_new.py +++ b/frappe/custom/doctype/test_rename_new/test_test_rename_new.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/database/database.py b/frappe/database/database.py index b29b4de252..6808f51d31 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -9,7 +9,6 @@ import string import traceback from contextlib import contextmanager from time import time -from typing import Dict, List, Optional, Tuple, Union from pypika.terms import Criterion, NullValue, PseudoColumn @@ -31,7 +30,7 @@ SINGLE_WORD_PATTERN = re.compile(r'([`"]?)(tab([A-Z]\w+))\1') MULTI_WORD_PATTERN = re.compile(r'([`"])(tab([A-Z]\w+)( [A-Z]\w+)+)\1') -class Database(object): +class Database: """ Open a database connection with the given parmeters, if use_default is True, use the login details from `conf.py`. This is called by the request handler and is accessible using @@ -684,8 +683,8 @@ class Database(object): def set_single_value( self, doctype: str, - fieldname: Union[str, Dict], - value: Optional[Union[str, int]] = None, + fieldname: str | dict, + value: str | int | None = None, *args, **kwargs, ): @@ -1061,13 +1060,13 @@ class Database(object): def count(self, dt, filters=None, debug=False, cache=False, distinct: bool = True): """Returns `COUNT(*)` for given DocType and filters.""" if cache and not filters: - cache_count = frappe.cache().get_value("doctype:count:{}".format(dt)) + cache_count = frappe.cache().get_value(f"doctype:count:{dt}") if cache_count is not None: return cache_count query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"), distinct=distinct) count = self.sql(query, debug=debug)[0][0] if not filters and cache: - frappe.cache().set_value("doctype:count:{}".format(dt), count, expires_in_sec=86400) + frappe.cache().set_value(f"doctype:count:{dt}", count, expires_in_sec=86400) return count @staticmethod @@ -1102,7 +1101,7 @@ class Database(object): .run()[0][0] ) - def get_db_table_columns(self, table) -> List[str]: + def get_db_table_columns(self, table) -> list[str]: """Returns list of column names from given table.""" columns = frappe.cache().hget("table_columns", table) if columns is None: @@ -1162,10 +1161,7 @@ class Database(object): return INDEX_PATTERN.sub(r"", index_name) def get_system_setting(self, key): - def _load_system_settings(): - return self.get_singles_dict("System Settings") - - return frappe.cache().get_value("system_settings", _load_system_settings).get(key) + return frappe.get_system_settings(key) def close(self): """Close database connection.""" @@ -1202,7 +1198,7 @@ class Database(object): query = sql_dict.get(current_dialect) return self.sql(query, values, **kwargs) - def delete(self, doctype: str, filters: Union[Dict, List] = None, debug=False, **kwargs): + def delete(self, doctype: str, filters: dict | list = None, debug=False, **kwargs): """Delete rows from a table in site which match the passed filters. This does trigger DocType hooks. Simply runs a DELETE query in the database. @@ -1306,7 +1302,7 @@ def enqueue_jobs_after_commit(): @contextmanager -def savepoint(catch: Union[type, Tuple[type, ...]] = Exception): +def savepoint(catch: type | tuple[type, ...] = Exception): """Wrapper for wrapping blocks of DB operations in a savepoint. as contextmanager: diff --git a/frappe/database/db_manager.py b/frappe/database/db_manager.py index f69c93db0f..3dddb7f862 100644 --- a/frappe/database/db_manager.py +++ b/frappe/database/db_manager.py @@ -59,11 +59,11 @@ class DbManager: pv = find_executable("pv") if pv: - pipe = "{pv} {source} |".format(pv=pv, source=source) + pipe = f"{pv} {source} |" source = "" else: pipe = "" - source = "< {source}".format(source=source) + source = f"< {source}" if pipe: print("Restoring Database file...") diff --git a/frappe/database/mariadb/database.py b/frappe/database/mariadb/database.py index b620c235a3..671b28d168 100644 --- a/frappe/database/mariadb/database.py +++ b/frappe/database/mariadb/database.py @@ -1,6 +1,6 @@ import re from collections import defaultdict -from typing import TYPE_CHECKING, Dict, List, Tuple, Union +from typing import TYPE_CHECKING import mariadb from mariadb.constants import FIELD_TYPE @@ -196,7 +196,7 @@ class MariaDBConnectionUtil: def create_connection(self): return mariadb.connect(**self.get_connection_settings()) - def get_connection_settings(self) -> Dict: + def get_connection_settings(self) -> dict: conn_settings = { "host": self.host, "user": self.user, @@ -227,7 +227,7 @@ class MariaDBConnectionUtil: conn_settings.update(ssl_params) return conn_settings - def _transform_query(self, query: str, values: Dict) -> str: + def _transform_query(self, query: str, values: dict) -> str: """Converts a query with named placeholders to a query with %s and values dict to a tuple. This is a workaround since the MariaDB Python client (1.0.11) responds inconsistently @@ -367,18 +367,18 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): def is_type_datetime(code): return code == mariadb.DATETIME - def rename_table(self, old_name: str, new_name: str) -> Union[List, Tuple]: + def rename_table(self, old_name: str, new_name: str) -> list | tuple: old_name = get_table_name(old_name) new_name = get_table_name(new_name) return self.sql(f"RENAME TABLE `{old_name}` TO `{new_name}`") - def describe(self, doctype: str) -> Union[List, Tuple]: + def describe(self, doctype: str) -> list | tuple: table_name = get_table_name(doctype) return self.sql(f"DESC `{table_name}`") def change_column_type( self, doctype: str, column: str, type: str, nullable: bool = False - ) -> Union[List, Tuple]: + ) -> list | tuple: table_name = get_table_name(doctype) null_constraint = "NOT NULL" if not nullable else "" return self.sql_ddl(f"ALTER TABLE `{table_name}` MODIFY `{column}` {type} {null_constraint}") @@ -459,7 +459,7 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): ) ) - def add_index(self, doctype: str, fields: List, index_name: str = None): + def add_index(self, doctype: str, fields: list, index_name: str = None): """Creates an index with given fields if not already created. Index name will be `fieldname1_fieldname2_index`""" index_name = index_name or self.get_index_name(fields) @@ -499,7 +499,7 @@ class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): """ res = self.sql("select issingle from `tabDocType` where name=%s", (doctype,)) if not res: - raise Exception("Wrong doctype {0} in updatedb".format(doctype)) + raise Exception(f"Wrong doctype {doctype} in updatedb") if not res[0][0]: db_table = MariaDBTable(doctype, meta) diff --git a/frappe/database/mariadb/schema.py b/frappe/database/mariadb/schema.py index f402b4ec74..24a78012e1 100644 --- a/frappe/database/mariadb/schema.py +++ b/frappe/database/mariadb/schema.py @@ -77,15 +77,15 @@ class MariaDBTable(DBTable): columns_to_modify = set(self.change_type + self.add_unique + self.set_default) for col in self.add_column: - add_column_query.append("ADD COLUMN `{}` {}".format(col.fieldname, col.get_definition())) + add_column_query.append(f"ADD COLUMN `{col.fieldname}` {col.get_definition()}") for col in columns_to_modify: - modify_column_query.append("MODIFY `{}` {}".format(col.fieldname, col.get_definition())) + modify_column_query.append(f"MODIFY `{col.fieldname}` {col.get_definition()}") for col in self.add_index: # if index key does not exists if not frappe.db.has_index(self.table_name, col.fieldname + "_index"): - add_index_query.append("ADD INDEX `{}_index`(`{}`)".format(col.fieldname, col.fieldname)) + add_index_query.append(f"ADD INDEX `{col.fieldname}_index`(`{col.fieldname}`)") for col in self.drop_index + self.drop_unique: if col.fieldname != "name": # primary key @@ -95,7 +95,7 @@ class MariaDBTable(DBTable): # nosemgrep unique_index_record = frappe.db.sql( """ - SHOW INDEX FROM `{0}` + SHOW INDEX FROM `{}` WHERE Key_name=%s AND Non_unique=0 """.format( @@ -105,14 +105,14 @@ class MariaDBTable(DBTable): as_dict=1, ) if unique_index_record: - drop_index_query.append("DROP INDEX `{}`".format(unique_index_record[0].Key_name)) + drop_index_query.append(f"DROP INDEX `{unique_index_record[0].Key_name}`") index_constraint_changed = current_column.index != col.set_index # if index key exists if index_constraint_changed and not col.set_index: # nosemgrep index_record = frappe.db.sql( """ - SHOW INDEX FROM `{0}` + SHOW INDEX FROM `{}` WHERE Key_name=%s AND Non_unique=1 """.format( @@ -122,13 +122,13 @@ class MariaDBTable(DBTable): as_dict=1, ) if index_record: - drop_index_query.append("DROP INDEX `{}`".format(index_record[0].Key_name)) + drop_index_query.append(f"DROP INDEX `{index_record[0].Key_name}`") try: for query_parts in [add_column_query, modify_column_query, add_index_query, drop_index_query]: if query_parts: query_body = ", ".join(query_parts) - query = "ALTER TABLE `{}` {}".format(self.table_name, query_body) + query = f"ALTER TABLE `{self.table_name}` {query_body}" frappe.db.sql(query) except Exception as e: diff --git a/frappe/database/mariadb/setup_db.py b/frappe/database/mariadb/setup_db.py index c26aaea343..ef246712b1 100644 --- a/frappe/database/mariadb/setup_db.py +++ b/frappe/database/mariadb/setup_db.py @@ -42,7 +42,7 @@ def setup_database(force, source_sql, verbose, no_mariadb_socket=False): dbman.delete_user(db_name, **dbman_kwargs) dbman.drop_database(db_name) else: - raise Exception("Database %s already exists" % (db_name,)) + raise Exception(f"Database {db_name} already exists") dbman.create_user(db_name, frappe.conf.db_password, **dbman_kwargs) if verbose: @@ -55,7 +55,7 @@ def setup_database(force, source_sql, verbose, no_mariadb_socket=False): dbman.grant_all_privileges(db_name, db_name, **dbman_kwargs) dbman.flush_privileges() if verbose: - print("Granted privileges to user %s and database %s" % (db_name, db_name)) + print(f"Granted privileges to user {db_name} and database {db_name}") # close root connection root_conn.close() diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index 6dd269a213..ec3e0084f9 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -1,5 +1,4 @@ import re -from typing import List, Tuple, Union import psycopg2 import psycopg2.extensions @@ -190,9 +189,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): # pylint: disable=W0221 def sql(self, query, values=(), *args, **kwargs): - return super(PostgresDatabase, self).sql( - modify_query(query), modify_values(values), *args, **kwargs - ) + return super().sql(modify_query(query), modify_values(values), *args, **kwargs) def lazy_mogrify(self, *args, **kwargs) -> str: return self.last_query @@ -203,9 +200,9 @@ class PostgresDatabase(PostgresExceptionUtil, Database): for d in self.sql( """select table_name from information_schema.tables - where table_catalog='{0}' + where table_catalog='{}' and table_type = 'BASE TABLE' - and table_schema='{1}'""".format( + and table_schema='{}'""".format( frappe.conf.db_name, frappe.conf.get("db_schema", "public") ) ) @@ -229,12 +226,12 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def is_type_datetime(code): return code == psycopg2.DATETIME - def rename_table(self, old_name: str, new_name: str) -> Union[List, Tuple]: + def rename_table(self, old_name: str, new_name: str) -> list | tuple: old_name = get_table_name(old_name) new_name = get_table_name(new_name) return self.sql(f"ALTER TABLE `{old_name}` RENAME TO `{new_name}`") - def describe(self, doctype: str) -> Union[List, Tuple]: + def describe(self, doctype: str) -> list | tuple: table_name = get_table_name(doctype) return self.sql( f"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = '{table_name}'" @@ -242,7 +239,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def change_column_type( self, doctype: str, column: str, type: str, nullable: bool = False, use_cast: bool = False - ) -> Union[List, Tuple]: + ) -> list | tuple: table_name = get_table_name(doctype) null_constraint = "SET NOT NULL" if not nullable else "DROP NOT NULL" using_cast = f'using "{column}"::{type}' if use_cast else "" @@ -300,9 +297,9 @@ class PostgresDatabase(PostgresExceptionUtil, Database): * updates columns * updates indices """ - res = self.sql("select issingle from `tabDocType` where name='{}'".format(doctype)) + res = self.sql(f"select issingle from `tabDocType` where name='{doctype}'") if not res: - raise Exception("Wrong doctype {0} in updatedb".format(doctype)) + raise Exception(f"Wrong doctype {doctype} in updatedb") if not res[0][0]: db_table = PostgresTable(doctype, meta) @@ -316,7 +313,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): def get_on_duplicate_update(key="name"): if isinstance(key, list): key = '", "'.join(key) - return 'ON CONFLICT ("{key}") DO UPDATE SET '.format(key=key) + return f'ON CONFLICT ("{key}") DO UPDATE SET ' def check_implicit_commit(self, query): pass # postgres can run DDL in transactions without implicit commits @@ -329,7 +326,7 @@ class PostgresDatabase(PostgresExceptionUtil, Database): ) ) - def add_index(self, doctype: str, fields: List, index_name: str = None): + def add_index(self, doctype: str, fields: list, index_name: str = None): """Creates an index with given fields if not already created. Index name will be `fieldname1_fieldname2_index`""" table_name = get_table_name(doctype) diff --git a/frappe/database/postgres/schema.py b/frappe/database/postgres/schema.py index ef7ba33e12..5e28c81455 100644 --- a/frappe/database/postgres/schema.py +++ b/frappe/database/postgres/schema.py @@ -79,7 +79,7 @@ class PostgresTable(DBTable): query = [] for col in self.add_column: - query.append("ADD COLUMN `{}` {}".format(col.fieldname, col.get_definition())) + query.append(f"ADD COLUMN `{col.fieldname}` {col.get_definition()}") for col in self.change_type: using_clause = "" @@ -87,12 +87,12 @@ class PostgresTable(DBTable): # The USING option of SET DATA TYPE can actually specify any expression # involving the old values of the row # read more https://www.postgresql.org/docs/9.1/sql-altertable.html - using_clause = "USING {}::timestamp without time zone".format(col.fieldname) + using_clause = f"USING {col.fieldname}::timestamp without time zone" elif col.fieldtype in ("Check"): - using_clause = "USING {}::smallint".format(col.fieldname) + using_clause = f"USING {col.fieldname}::smallint" query.append( - "ALTER COLUMN `{0}` TYPE {1} {2}".format( + "ALTER COLUMN `{}` TYPE {} {}".format( col.fieldname, get_definition(col.fieldtype, precision=col.precision, length=col.length), using_clause, @@ -113,9 +113,9 @@ class PostgresTable(DBTable): col_default = "NULL" else: - col_default = "{}".format(frappe.db.escape(col.default)) + col_default = f"{frappe.db.escape(col.default)}" - query.append("ALTER COLUMN `{}` SET DEFAULT {}".format(col.fieldname, col_default)) + query.append(f"ALTER COLUMN `{col.fieldname}` SET DEFAULT {col_default}") create_contraint_query = "" for col in self.add_index: @@ -139,13 +139,13 @@ class PostgresTable(DBTable): # primary key if col.fieldname != "name": # if index key exists - drop_contraint_query += 'DROP INDEX IF EXISTS "{}" ;'.format(col.fieldname) + drop_contraint_query += f'DROP INDEX IF EXISTS "{col.fieldname}" ;' for col in self.drop_unique: # primary key if col.fieldname != "name": # if index key exists - drop_contraint_query += 'DROP INDEX IF EXISTS "unique_{}" ;'.format(col.fieldname) + drop_contraint_query += f'DROP INDEX IF EXISTS "unique_{col.fieldname}" ;' try: if query: final_alter_query = "ALTER TABLE `{}` {}".format(self.table_name, ", ".join(query)) diff --git a/frappe/database/postgres/setup_db.py b/frappe/database/postgres/setup_db.py index 9a7f2b43c4..0a40e9eba7 100644 --- a/frappe/database/postgres/setup_db.py +++ b/frappe/database/postgres/setup_db.py @@ -7,12 +7,10 @@ def setup_database(force, source_sql=None, verbose=False): root_conn = get_root_connection(frappe.flags.root_login, frappe.flags.root_password) root_conn.commit() root_conn.sql("end") - root_conn.sql("DROP DATABASE IF EXISTS `{0}`".format(frappe.conf.db_name)) - root_conn.sql("DROP USER IF EXISTS {0}".format(frappe.conf.db_name)) - root_conn.sql("CREATE DATABASE `{0}`".format(frappe.conf.db_name)) - root_conn.sql( - "CREATE user {0} password '{1}'".format(frappe.conf.db_name, frappe.conf.db_password) - ) + root_conn.sql(f"DROP DATABASE IF EXISTS `{frappe.conf.db_name}`") + root_conn.sql(f"DROP USER IF EXISTS {frappe.conf.db_name}") + root_conn.sql(f"CREATE DATABASE `{frappe.conf.db_name}`") + root_conn.sql(f"CREATE user {frappe.conf.db_name} password '{frappe.conf.db_password}'") root_conn.sql("GRANT ALL PRIVILEGES ON DATABASE `{0}` TO {0}".format(frappe.conf.db_name)) root_conn.close() @@ -79,10 +77,10 @@ def import_db_from_sql(source_sql=None, verbose=False): def setup_help_database(help_db_name): root_conn = get_root_connection(frappe.flags.root_login, frappe.flags.root_password) - root_conn.sql("DROP DATABASE IF EXISTS `{0}`".format(help_db_name)) - root_conn.sql("DROP USER IF EXISTS {0}".format(help_db_name)) - root_conn.sql("CREATE DATABASE `{0}`".format(help_db_name)) - root_conn.sql("CREATE user {0} password '{1}'".format(help_db_name, help_db_name)) + root_conn.sql(f"DROP DATABASE IF EXISTS `{help_db_name}`") + root_conn.sql(f"DROP USER IF EXISTS {help_db_name}") + root_conn.sql(f"CREATE DATABASE `{help_db_name}`") + root_conn.sql(f"CREATE user {help_db_name} password '{help_db_name}'") root_conn.sql("GRANT ALL PRIVILEGES ON DATABASE `{0}` TO {0}".format(help_db_name)) diff --git a/frappe/database/query.py b/frappe/database/query.py index bd5b05fb3c..78d8d1d898 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -1,7 +1,7 @@ import operator import re from functools import cached_property -from typing import Any, Callable, Dict, List, Tuple, Union +from typing import Any, Callable import frappe from frappe import _ @@ -25,7 +25,7 @@ def like(key: Field, value: str) -> frappe.qb: return key.like(value) -def func_in(key: Field, value: Union[List, Tuple]) -> frappe.qb: +def func_in(key: Field, value: list | tuple) -> frappe.qb: """Wrapper method for `IN` Args: @@ -51,7 +51,7 @@ def not_like(key: Field, value: str) -> frappe.qb: return key.not_like(value) -def func_not_in(key: Field, value: Union[List, Tuple]): +def func_not_in(key: Field, value: list | tuple): """Wrapper method for `NOT IN` Args: @@ -77,7 +77,7 @@ def func_regex(key: Field, value: str) -> frappe.qb: return key.regex(value) -def func_between(key: Field, value: Union[List, Tuple]) -> frappe.qb: +def func_between(key: Field, value: list | tuple) -> frappe.qb: """Wrapper method for `BETWEEN` Args: @@ -109,7 +109,7 @@ def func_timespan(key: Field, value: str) -> frappe.qb: return func_between(key, get_timespan_date_range(value)) -def make_function(key: Any, value: Union[int, str]): +def make_function(key: Any, value: int | str): """returns fucntion query Args: @@ -143,7 +143,7 @@ def change_orderby(order: str): # default operators -OPERATOR_MAP: Dict[str, Callable] = { +OPERATOR_MAP: dict[str, Callable] = { "+": operator.add, "=": operator.eq, "-": operator.sub, @@ -186,7 +186,7 @@ class Query: return all_operators - def get_condition(self, table: Union[str, Table], **kwargs) -> frappe.qb: + def get_condition(self, table: str | Table, **kwargs) -> frappe.qb: """Get initial table object Args: @@ -202,7 +202,7 @@ class Query: return frappe.qb.into(table_object) return frappe.qb.from_(table_object) - def get_table(self, table_name: Union[str, Table]) -> Table: + def get_table(self, table_name: str | Table) -> Table: if isinstance(table_name, Table): return table_name table_name = table_name.strip('"').strip("'") @@ -253,7 +253,7 @@ class Query: return conditions - def misc_query(self, table: str, filters: Union[List, Tuple] = None, **kwargs): + def misc_query(self, table: str, filters: list | tuple = None, **kwargs): """Build conditions using the given Lists or Tuple filters Args: @@ -285,9 +285,7 @@ class Query: return self.add_conditions(conditions, **kwargs) - def dict_query( - self, table: str, filters: Dict[str, Union[str, int]] = None, **kwargs - ) -> frappe.qb: + def dict_query(self, table: str, filters: dict[str, str | int] = None, **kwargs) -> frappe.qb: """Build conditions using the given dictionary filters Args: @@ -323,7 +321,7 @@ class Query: return self.add_conditions(conditions, **kwargs) def build_conditions( - self, table: str, filters: Union[Dict[str, Union[str, int]], str, int] = None, **kwargs + self, table: str, filters: dict[str, str | int] | str | int = None, **kwargs ) -> frappe.qb: """Build conditions for sql query @@ -351,8 +349,8 @@ class Query: def get_sql( self, table: str, - fields: Union[List, Tuple], - filters: Union[Dict[str, Union[str, int]], str, int, List[Union[List, str, int]]] = None, + fields: list | tuple, + filters: dict[str, str | int] | str | int | list[list | str | int] = None, **kwargs, ): # Clean up state before each query diff --git a/frappe/database/schema.py b/frappe/database/schema.py index 9a8307ddae..5920d14c3d 100644 --- a/frappe/database/schema.py +++ b/frappe/database/schema.py @@ -15,7 +15,7 @@ class InvalidColumnName(frappe.ValidationError): class DBTable: def __init__(self, doctype, meta=None): self.doctype = doctype - self.table_name = "tab{}".format(doctype) + self.table_name = f"tab{doctype}" self.meta = meta or frappe.get_meta(doctype, False) self.columns = {} self.current_columns = {} @@ -195,11 +195,11 @@ class DbColumn: if self.fieldtype in ("Check", "Int"): default_value = cint(self.default) or 0 - column_def += " not null default {0}".format(default_value) + column_def += f" not null default {default_value}" elif self.fieldtype in ("Currency", "Float", "Percent"): default_value = flt(self.default) or 0 - column_def += " not null default {0}".format(default_value) + column_def += f" not null default {default_value}" elif ( self.default @@ -207,7 +207,7 @@ class DbColumn: and not cstr(self.default).startswith(":") and column_def not in ("text", "longtext") ): - column_def += " default {}".format(frappe.db.escape(self.default)) + column_def += f" default {frappe.db.escape(self.default)}" if self.unique and (column_def not in ("text", "longtext")): column_def += " unique" @@ -308,7 +308,7 @@ class DbColumn: def validate_column_name(n): if special_characters := SPECIAL_CHAR_PATTERN.findall(n): - special_characters = ", ".join('"{0}"'.format(c) for c in special_characters) + special_characters = ", ".join(f'"{c}"' for c in special_characters) frappe.throw( _("Fieldname {0} cannot have special characters like {1}").format( frappe.bold(cstr(n)), special_characters @@ -352,7 +352,7 @@ def get_definition(fieldtype, precision=None, length=None): size = length if size is not None: - coltype = "{coltype}({size})".format(coltype=coltype, size=size) + coltype = f"{coltype}({size})" return coltype @@ -366,7 +366,7 @@ def add_column( frappe.db.commit() - query = "alter table `tab%s` add column %s %s" % ( + query = "alter table `tab{}` add column {} {}".format( doctype, column_name, get_definition(fieldtype, precision, length), diff --git a/frappe/database/utils.py b/frappe/database/utils.py index 6da4aade4a..e71ffbf0d6 100644 --- a/frappe/database/utils.py +++ b/frappe/database/utils.py @@ -2,21 +2,16 @@ # License: MIT. See LICENSE from functools import cached_property - -try: - from types import NoneType -except ImportError: - NoneType = type(None) -from typing import Dict, List, Tuple, Union +from types import NoneType import frappe from frappe.query_builder.builder import MariaDB, Postgres -Query = Union[str, MariaDB, Postgres] -QueryValues = Union[Tuple, List, Dict, NoneType] +Query = str | MariaDB | Postgres +QueryValues = tuple | list | dict | NoneType -def is_query_type(query: str, query_type: Union[str, Tuple[str]]) -> bool: +def is_query_type(query: str, query_type: str | tuple[str]) -> bool: return query.lstrip().split(maxsplit=1)[0].lower().startswith(query_type) diff --git a/frappe/deferred_insert.py b/frappe/deferred_insert.py index 3b47d46cdf..328d8dd555 100644 --- a/frappe/deferred_insert.py +++ b/frappe/deferred_insert.py @@ -1,5 +1,5 @@ import json -from typing import TYPE_CHECKING, Dict, List, Union +from typing import TYPE_CHECKING, Union import redis @@ -12,7 +12,7 @@ if TYPE_CHECKING: queue_prefix = "insert_queue_for_" -def deferred_insert(doctype: str, records: Union[List[Union[Dict, "Document"]], str]): +def deferred_insert(doctype: str, records: list[Union[dict, "Document"]] | str): if isinstance(records, (dict, list)): _records = json.dumps(records) else: @@ -43,7 +43,7 @@ def save_to_db(): insert_record(record, doctype) -def insert_record(record: Union[Dict, "Document"], doctype: str): +def insert_record(record: Union[dict, "Document"], doctype: str): try: record.update({"doctype": doctype}) frappe.get_doc(record).insert() diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index ca0d1e2353..e2be2656a9 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -486,9 +486,9 @@ def save_new_widget(doc, page, blocks, new_widgets): # Error log body log = """ - page: {0} - config: {1} - exception: {2} + page: {} + config: {} + exception: {} """.format( page, json_config, e ) diff --git a/frappe/desk/doctype/bulk_update/bulk_update.py b/frappe/desk/doctype/bulk_update/bulk_update.py index dc0a88178d..1e515bbc47 100644 --- a/frappe/desk/doctype/bulk_update/bulk_update.py +++ b/frappe/desk/doctype/bulk_update/bulk_update.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -24,7 +23,7 @@ def update(doctype, field, value, condition="", limit=500): frappe.throw(_("; not allowed in condition")) docnames = frappe.db.sql_list( - """select name from `tab{0}`{1} limit {2} offset 0""".format(doctype, condition, limit) + f"""select name from `tab{doctype}`{condition} limit {limit} offset 0""" ) data = {} data[field] = value diff --git a/frappe/desk/doctype/calendar_view/calendar_view.py b/frappe/desk/doctype/calendar_view/calendar_view.py index 01968e835d..1e187682ec 100644 --- a/frappe/desk/doctype/calendar_view/calendar_view.py +++ b/frappe/desk/doctype/calendar_view/calendar_view.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/console_log/console_log.py b/frappe/desk/doctype/console_log/console_log.py index ebe93f535d..7e20afb22f 100644 --- a/frappe/desk/doctype/console_log/console_log.py +++ b/frappe/desk/doctype/console_log/console_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/console_log/test_console_log.py b/frappe/desk/doctype/console_log/test_console_log.py index 409ac88299..0579098382 100644 --- a/frappe/desk/doctype/console_log/test_console_log.py +++ b/frappe/desk/doctype/console_log/test_console_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index 61e997836c..960431d220 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -115,7 +115,7 @@ def get_non_standard_warning_message(non_standard_docs_map): message = _("""Please set the following documents in this Dashboard as standard first.""") def get_html(docs, doctype): - html = "

{}

".format(frappe.bold(doctype)) + html = f"

{frappe.bold(doctype)}

" for doc in docs: html += ''.format( doctype=doctype, doc=doc diff --git a/frappe/desk/doctype/dashboard/test_dashboard.py b/frappe/desk/doctype/dashboard/test_dashboard.py index ee3d1848e2..d2ba871509 100644 --- a/frappe/desk/doctype/dashboard/test_dashboard.py +++ b/frappe/desk/doctype/dashboard/test_dashboard.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index ca29bad33b..1145873a09 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -212,7 +211,7 @@ def get_chart_config(chart, filters, timespan, timegrain, from_date, to_date): data = frappe.db.get_list( doctype, - fields=["{} as _unit".format(datefield), "SUM({})".format(value_field), "COUNT(*)"], + fields=[f"{datefield} as _unit", f"SUM({value_field})", "COUNT(*)"], filters=filters, group_by="_unit", order_by="_unit asc", @@ -242,13 +241,13 @@ def get_heatmap_chart_config(chart, filters, heatmap_year): year_start_date = datetime.date(year, 1, 1).strftime("%Y-%m-%d") next_year_start_date = datetime.date(year + 1, 1, 1).strftime("%Y-%m-%d") - filters.append([doctype, datefield, ">", "{date}".format(date=year_start_date), False]) - filters.append([doctype, datefield, "<", "{date}".format(date=next_year_start_date), False]) + filters.append([doctype, datefield, ">", f"{year_start_date}", False]) + filters.append([doctype, datefield, "<", f"{next_year_start_date}", False]) if frappe.db.db_type == "mariadb": - timestamp_field = "unix_timestamp({datefield})".format(datefield=datefield) + timestamp_field = f"unix_timestamp({datefield})" else: - timestamp_field = "extract(epoch from timestamp {datefield})".format(datefield=datefield) + timestamp_field = f"extract(epoch from timestamp {datefield})" data = dict( frappe.db.get_all( @@ -260,9 +259,9 @@ def get_heatmap_chart_config(chart, filters, heatmap_year): ), ], filters=filters, - group_by="date({datefield})".format(datefield=datefield), + group_by=f"date({datefield})", as_list=1, - order_by="{datefield} asc".format(datefield=datefield), + order_by=f"{datefield} asc", ignore_ifnull=True, ) ) @@ -284,7 +283,7 @@ def get_group_by_chart_config(chart, filters): data = frappe.db.get_list( doctype, fields=[ - "{} as name".format(group_by_field), + f"{group_by_field} as name", "{aggregate_function}({value_field}) as count".format( aggregate_function=aggregate_function, value_field=value_field ), @@ -351,7 +350,7 @@ def get_charts_for_user(doctype, txt, searchfield, start, page_len, filters): class DashboardChart(Document): def on_update(self): - frappe.cache().delete_key("chart-data:{}".format(self.name)) + frappe.cache().delete_key(f"chart-data:{self.name}") if frappe.conf.developer_mode and self.is_standard: export_to_files(record_list=[["Dashboard Chart", self.name]], record_module=self.module) diff --git a/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py index ca84b2c301..820f3c0555 100644 --- a/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/test_dashboard_chart.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/dashboard_chart_field/dashboard_chart_field.py b/frappe/desk/doctype/dashboard_chart_field/dashboard_chart_field.py index 41f35d2ee4..adc03663a2 100644 --- a/frappe/desk/doctype/dashboard_chart_field/dashboard_chart_field.py +++ b/frappe/desk/doctype/dashboard_chart_field/dashboard_chart_field.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/dashboard_chart_link/dashboard_chart_link.py b/frappe/desk/doctype/dashboard_chart_link/dashboard_chart_link.py index b2a7caefeb..4d98b69458 100644 --- a/frappe/desk/doctype/dashboard_chart_link/dashboard_chart_link.py +++ b/frappe/desk/doctype/dashboard_chart_link/dashboard_chart_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/dashboard_chart_source/dashboard_chart_source.py b/frappe/desk/doctype/dashboard_chart_source/dashboard_chart_source.py index 155a71a9b4..5519ad9097 100644 --- a/frappe/desk/doctype/dashboard_chart_source/dashboard_chart_source.py +++ b/frappe/desk/doctype/dashboard_chart_source/dashboard_chart_source.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -17,7 +16,6 @@ def get_config(name): os.path.join( get_module_path(doc.module), "dashboard_chart_source", scrub(doc.name), scrub(doc.name) + ".js" ), - "r", ) as f: return f.read() diff --git a/frappe/desk/doctype/dashboard_chart_source/test_dashboard_chart_source.py b/frappe/desk/doctype/dashboard_chart_source/test_dashboard_chart_source.py index 0c219c08cc..457487bb6d 100644 --- a/frappe/desk/doctype/dashboard_chart_source/test_dashboard_chart_source.py +++ b/frappe/desk/doctype/dashboard_chart_source/test_dashboard_chart_source.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/desk/doctype/dashboard_settings/dashboard_settings.py b/frappe/desk/doctype/dashboard_settings/dashboard_settings.py index 01c3a87f20..489beda0bf 100644 --- a/frappe/desk/doctype/dashboard_settings/dashboard_settings.py +++ b/frappe/desk/doctype/dashboard_settings/dashboard_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -28,7 +27,7 @@ def get_permission_query_conditions(user): if not user: user = frappe.session.user - return """(`tabDashboard Settings`.name = {user})""".format(user=frappe.db.escape(user)) + return f"""(`tabDashboard Settings`.name = {frappe.db.escape(user)})""" @frappe.whitelist() diff --git a/frappe/desk/doctype/desktop_icon/desktop_icon.py b/frappe/desk/doctype/desktop_icon/desktop_icon.py index 29de1f56d9..5602f4da24 100644 --- a/frappe/desk/doctype/desktop_icon/desktop_icon.py +++ b/frappe/desk/doctype/desktop_icon/desktop_icon.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE @@ -133,7 +132,7 @@ def add_user_icon(_doctype, _report=None, label=None, link=None, type="link", st if not label: label = _doctype or _report if not link: - link = "List/{0}".format(_doctype) + link = f"List/{_doctype}" # find if a standard icon exists icon_name = frappe.db.exists( diff --git a/frappe/desk/doctype/event/event.py b/frappe/desk/doctype/event/event.py index 6fdc95d3d0..e9104ef897 100644 --- a/frappe/desk/doctype/event/event.py +++ b/frappe/desk/doctype/event/event.py @@ -161,9 +161,9 @@ 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)s)""" % { - "user": frappe.db.escape(user), - } + return """(`tabEvent`.`event_type`='Public' or `tabEvent`.`owner`={user})""".format( + user=frappe.db.escape(user), + ) def has_permission(doc, user): diff --git a/frappe/desk/doctype/event/test_event.py b/frappe/desk/doctype/event/test_event.py index 041bda643e..efbd54fb09 100644 --- a/frappe/desk/doctype/event/test_event.py +++ b/frappe/desk/doctype/event/test_event.py @@ -96,7 +96,7 @@ class TestEvent(unittest.TestCase): ev = frappe.get_doc("Event", ev.name) - self.assertEqual(set(json.loads(ev._assign)), set(["test@example.com", self.test_user])) + self.assertEqual(set(json.loads(ev._assign)), {"test@example.com", self.test_user}) # Remove an assignment todo = frappe.get_doc( diff --git a/frappe/desk/doctype/event_participants/event_participants.py b/frappe/desk/doctype/event_participants/event_participants.py index fdb834b285..869ae4092b 100644 --- a/frappe/desk/doctype/event_participants/event_participants.py +++ b/frappe/desk/doctype/event_participants/event_participants.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE from frappe.model.document import Document diff --git a/frappe/desk/doctype/global_search_doctype/global_search_doctype.py b/frappe/desk/doctype/global_search_doctype/global_search_doctype.py index 8bdc05cd71..48fdb3d4d1 100644 --- a/frappe/desk/doctype/global_search_doctype/global_search_doctype.py +++ b/frappe/desk/doctype/global_search_doctype/global_search_doctype.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/global_search_settings/global_search_settings.py b/frappe/desk/doctype/global_search_settings/global_search_settings.py index b7ffd7faf7..4e2b1e85f9 100644 --- a/frappe/desk/doctype/global_search_settings/global_search_settings.py +++ b/frappe/desk/doctype/global_search_settings/global_search_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/kanban_board/kanban_board.py b/frappe/desk/doctype/kanban_board/kanban_board.py index bc47bbbaf4..83f0f46df0 100644 --- a/frappe/desk/doctype/kanban_board/kanban_board.py +++ b/frappe/desk/doctype/kanban_board/kanban_board.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -126,7 +125,7 @@ def update_order_for_single_card( if from_colname == to_colname: from_col_order = to_col_order - to_col_order.insert(new_index, from_col_order.pop((old_index))) + to_col_order.insert(new_index, from_col_order.pop(old_index)) # save updated order board.columns[from_col_idx].order = frappe.as_json(from_col_order) @@ -173,7 +172,7 @@ def quick_kanban_board(doctype, board_name, field_name, project=None): doc.field_name = field_name if project: - doc.filters = '[["Task","project","=","{0}"]]'.format(project) + doc.filters = f'[["Task","project","=","{project}"]]' options = "" for field in meta.fields: diff --git a/frappe/desk/doctype/kanban_board/test_kanban_board.py b/frappe/desk/doctype/kanban_board/test_kanban_board.py index d4504bf9d8..73f566b906 100644 --- a/frappe/desk/doctype/kanban_board/test_kanban_board.py +++ b/frappe/desk/doctype/kanban_board/test_kanban_board.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/desk/doctype/kanban_board_column/kanban_board_column.py b/frappe/desk/doctype/kanban_board_column/kanban_board_column.py index d905369a0b..e57d92857e 100644 --- a/frappe/desk/doctype/kanban_board_column/kanban_board_column.py +++ b/frappe/desk/doctype/kanban_board_column/kanban_board_column.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/list_filter/list_filter.py b/frappe/desk/doctype/list_filter/list_filter.py index a5ba12df6a..e4c59ee9e4 100644 --- a/frappe/desk/doctype/list_filter/list_filter.py +++ b/frappe/desk/doctype/list_filter/list_filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/list_view_settings/list_view_settings.py b/frappe/desk/doctype/list_view_settings/list_view_settings.py index 7d25f57acf..36ebce34d5 100644 --- a/frappe/desk/doctype/list_view_settings/list_view_settings.py +++ b/frappe/desk/doctype/list_view_settings/list_view_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/list_view_settings/test_list_view_settings.py b/frappe/desk/doctype/list_view_settings/test_list_view_settings.py index 0b6a0773e3..0eab9cd7a6 100644 --- a/frappe/desk/doctype/list_view_settings/test_list_view_settings.py +++ b/frappe/desk/doctype/list_view_settings/test_list_view_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/desk/doctype/module_onboarding/module_onboarding.py b/frappe/desk/doctype/module_onboarding/module_onboarding.py index 7a12328ee0..ea02f5911d 100644 --- a/frappe/desk/doctype/module_onboarding/module_onboarding.py +++ b/frappe/desk/doctype/module_onboarding/module_onboarding.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/module_onboarding/test_module_onboarding.py b/frappe/desk/doctype/module_onboarding/test_module_onboarding.py index 8def3ac40e..fa19794c1e 100644 --- a/frappe/desk/doctype/module_onboarding/test_module_onboarding.py +++ b/frappe/desk/doctype/module_onboarding/test_module_onboarding.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/desk/doctype/note/note.py b/frappe/desk/doctype/note/note.py index a709b80f1d..c0a37d5f44 100644 --- a/frappe/desk/doctype/note/note.py +++ b/frappe/desk/doctype/note/note.py @@ -40,7 +40,7 @@ def get_permission_query_conditions(user): if user == "Administrator": return "" - return """(`tabNote`.public=1 or `tabNote`.owner={user})""".format(user=frappe.db.escape(user)) + return f"""(`tabNote`.public=1 or `tabNote`.owner={frappe.db.escape(user)})""" def has_permission(doc, ptype, user): diff --git a/frappe/desk/doctype/note_seen_by/note_seen_by.py b/frappe/desk/doctype/note_seen_by/note_seen_by.py index 7dde133e6d..5acdca222e 100644 --- a/frappe/desk/doctype/note_seen_by/note_seen_by.py +++ b/frappe/desk/doctype/note_seen_by/note_seen_by.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py index def626513c..3d16bdf32f 100644 --- a/frappe/desk/doctype/notification_log/notification_log.py +++ b/frappe/desk/doctype/notification_log/notification_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -29,7 +28,7 @@ def get_permission_query_conditions(for_user): if for_user == "Administrator": return - return """(`tabNotification Log`.for_user = {user})""".format(user=frappe.db.escape(for_user)) + return f"""(`tabNotification Log`.for_user = {frappe.db.escape(for_user)})""" def get_title(doctype, docname, title_field=None): @@ -40,7 +39,7 @@ def get_title(doctype, docname, title_field=None): def get_title_html(title): - return '{0}'.format(title) + return f'{title}' def enqueue_create_notification(users, doc): diff --git a/frappe/desk/doctype/notification_log/test_notification_log.py b/frappe/desk/doctype/notification_log/test_notification_log.py index 44b1b53ead..532f05ab57 100644 --- a/frappe/desk/doctype/notification_log/test_notification_log.py +++ b/frappe/desk/doctype/notification_log/test_notification_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/desk/doctype/notification_settings/notification_settings.py b/frappe/desk/doctype/notification_settings/notification_settings.py index 2bf7347a4f..801d512fe7 100644 --- a/frappe/desk/doctype/notification_settings/notification_settings.py +++ b/frappe/desk/doctype/notification_settings/notification_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -88,7 +87,7 @@ def get_permission_query_conditions(user): if "System Manager" in roles: return """(`tabNotification Settings`.name != 'Administrator')""" - return """(`tabNotification Settings`.name = {user})""".format(user=frappe.db.escape(user)) + return f"""(`tabNotification Settings`.name = {frappe.db.escape(user)})""" @frappe.whitelist() diff --git a/frappe/desk/doctype/notification_subscribed_document/notification_subscribed_document.py b/frappe/desk/doctype/notification_subscribed_document/notification_subscribed_document.py index b72f827cd7..551ee6dc85 100644 --- a/frappe/desk/doctype/notification_subscribed_document/notification_subscribed_document.py +++ b/frappe/desk/doctype/notification_subscribed_document/notification_subscribed_document.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/number_card/number_card.py b/frappe/desk/doctype/number_card/number_card.py index 74c8e9eb99..1bffd68940 100644 --- a/frappe/desk/doctype/number_card/number_card.py +++ b/frappe/desk/doctype/number_card/number_card.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -120,7 +119,7 @@ def get_result(doc, filters, to_date=None): function = sql_function_map[doc.function] if function == "count": - fields = ["{function}(*) as result".format(function=function)] + fields = [f"{function}(*) as result"] else: fields = [ "{function}({based_on}) as result".format( @@ -202,7 +201,7 @@ def get_cards_for_user(doctype, txt, searchfield, start, page_len, filters): numberCard = DocType("Number Card") if txt: - search_conditions = [numberCard[field].like("%{txt}%".format(txt=txt)) for field in searchfields] + search_conditions = [numberCard[field].like(f"%{txt}%") for field in searchfields] condition_query = frappe.db.query.build_conditions(doctype, filters) diff --git a/frappe/desk/doctype/number_card/test_number_card.py b/frappe/desk/doctype/number_card/test_number_card.py index 817ea2fad4..c0dda40104 100644 --- a/frappe/desk/doctype/number_card/test_number_card.py +++ b/frappe/desk/doctype/number_card/test_number_card.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/desk/doctype/number_card_link/number_card_link.py b/frappe/desk/doctype/number_card_link/number_card_link.py index b630d7caa7..16cc7ba4e3 100644 --- a/frappe/desk/doctype/number_card_link/number_card_link.py +++ b/frappe/desk/doctype/number_card_link/number_card_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/onboarding_permission/onboarding_permission.py b/frappe/desk/doctype/onboarding_permission/onboarding_permission.py index a0e87c3067..d7db13762a 100644 --- a/frappe/desk/doctype/onboarding_permission/onboarding_permission.py +++ b/frappe/desk/doctype/onboarding_permission/onboarding_permission.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/onboarding_permission/test_onboarding_permission.py b/frappe/desk/doctype/onboarding_permission/test_onboarding_permission.py index 9a12b0aab9..cdfe0d7890 100644 --- a/frappe/desk/doctype/onboarding_permission/test_onboarding_permission.py +++ b/frappe/desk/doctype/onboarding_permission/test_onboarding_permission.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/desk/doctype/onboarding_step/onboarding_step.py b/frappe/desk/doctype/onboarding_step/onboarding_step.py index 4a4d487cc8..b6807b62bd 100644 --- a/frappe/desk/doctype/onboarding_step/onboarding_step.py +++ b/frappe/desk/doctype/onboarding_step/onboarding_step.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/onboarding_step/test_onboarding_step.py b/frappe/desk/doctype/onboarding_step/test_onboarding_step.py index 2342656a72..d8bf55584c 100644 --- a/frappe/desk/doctype/onboarding_step/test_onboarding_step.py +++ b/frappe/desk/doctype/onboarding_step/test_onboarding_step.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/desk/doctype/onboarding_step_map/onboarding_step_map.py b/frappe/desk/doctype/onboarding_step_map/onboarding_step_map.py index 7c20e220db..8844316e68 100644 --- a/frappe/desk/doctype/onboarding_step_map/onboarding_step_map.py +++ b/frappe/desk/doctype/onboarding_step_map/onboarding_step_map.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/system_console/system_console.py b/frappe/desk/doctype/system_console/system_console.py index 063b3d37d0..993af6e753 100644 --- a/frappe/desk/doctype/system_console/system_console.py +++ b/frappe/desk/doctype/system_console/system_console.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/system_console/test_system_console.py b/frappe/desk/doctype/system_console/test_system_console.py index 372cbbc1f4..96bf555f59 100644 --- a/frappe/desk/doctype/system_console/test_system_console.py +++ b/frappe/desk/doctype/system_console/test_system_console.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/desk/doctype/tag/tag.py b/frappe/desk/doctype/tag/tag.py index aabf0351a5..ca167c148e 100644 --- a/frappe/desk/doctype/tag/tag.py +++ b/frappe/desk/doctype/tag/tag.py @@ -56,7 +56,7 @@ def get_tagged_docs(doctype, tag): @frappe.whitelist() def get_tags(doctype, txt): - tag = frappe.get_list("Tag", filters=[["name", "like", "%{}%".format(txt)]]) + tag = frappe.get_list("Tag", filters=[["name", "like", f"%{txt}%"]]) tags = [t.name for t in tag] return sorted(filter(lambda t: t and txt.lower() in t.lower(), list(set(tags)))) @@ -104,7 +104,7 @@ class DocTags: tags = "," + ",".join(tl) try: frappe.db.sql( - "update `tab%s` set _user_tags=%s where name=%s" % (self.dt, "%s", "%s"), (tags, dn) + "update `tab{}` set _user_tags={} where name={}".format(self.dt, "%s", "%s"), (tags, dn) ) doc = frappe.get_doc(self.dt, dn) update_tags(doc, tags) diff --git a/frappe/desk/doctype/tag_link/tag_link.py b/frappe/desk/doctype/tag_link/tag_link.py index ec816352ca..a67e6a62d3 100644 --- a/frappe/desk/doctype/tag_link/tag_link.py +++ b/frappe/desk/doctype/tag_link/tag_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/tag_link/test_tag_link.py b/frappe/desk/doctype/tag_link/test_tag_link.py index d4d1dd61fa..59d7bcd2bc 100644 --- a/frappe/desk/doctype/tag_link/test_tag_link.py +++ b/frappe/desk/doctype/tag_link/test_tag_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/desk/doctype/todo/test_todo.py b/frappe/desk/doctype/todo/test_todo.py index 5c54889e00..56ca1f30e7 100644 --- a/frappe/desk/doctype/todo/test_todo.py +++ b/frappe/desk/doctype/todo/test_todo.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/desk/doctype/workspace/test_workspace.py b/frappe/desk/doctype/workspace/test_workspace.py index 9281240e08..d0b0eba9e2 100644 --- a/frappe/desk/doctype/workspace/test_workspace.py +++ b/frappe/desk/doctype/workspace/test_workspace.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/desk/doctype/workspace/workspace.py b/frappe/desk/doctype/workspace/workspace.py index 284fecbe31..9fa99884fb 100644 --- a/frappe/desk/doctype/workspace/workspace.py +++ b/frappe/desk/doctype/workspace/workspace.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -206,7 +205,7 @@ def update_page(name, title, icon, parent, public): doc.sequence_id = frappe.db.count("Workspace", {"public": public}, cache=True) doc.public = public doc.for_user = "" if public else doc.for_user or frappe.session.user - doc.label = new_name = "{0}-{1}".format(title, doc.for_user) if doc.for_user else title + doc.label = new_name = f"{title}-{doc.for_user}" if doc.for_user else title doc.save(ignore_permissions=True) if name != new_name: @@ -221,9 +220,7 @@ def update_page(name, title, icon, parent, public): child_doc.public = public child_doc.for_user = "" if public else child_doc.for_user or frappe.session.user child_doc.label = new_child_name = ( - "{0}-{1}".format(child_doc.title, child_doc.for_user) - if child_doc.for_user - else child_doc.title + f"{child_doc.title}-{child_doc.for_user}" if child_doc.for_user else child_doc.title ) child_doc.save(ignore_permissions=True) @@ -253,7 +250,7 @@ def duplicate_page(page_name, new_page): doc.label = doc.title if not doc.public: doc.for_user = doc.for_user or frappe.session.user - doc.label = "{0}-{1}".format(doc.title, doc.for_user) + doc.label = f"{doc.title}-{doc.for_user}" doc.name = doc.label if old_doc.public == doc.public: doc.sequence_id += 0.1 diff --git a/frappe/desk/doctype/workspace_chart/workspace_chart.py b/frappe/desk/doctype/workspace_chart/workspace_chart.py index e02cf06ee0..45f4229401 100644 --- a/frappe/desk/doctype/workspace_chart/workspace_chart.py +++ b/frappe/desk/doctype/workspace_chart/workspace_chart.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/workspace_link/workspace_link.py b/frappe/desk/doctype/workspace_link/workspace_link.py index 5e55a7c2bd..5756846f38 100644 --- a/frappe/desk/doctype/workspace_link/workspace_link.py +++ b/frappe/desk/doctype/workspace_link/workspace_link.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/doctype/workspace_shortcut/workspace_shortcut.py b/frappe/desk/doctype/workspace_shortcut/workspace_shortcut.py index 4ca86c8146..49ba37854c 100644 --- a/frappe/desk/doctype/workspace_shortcut/workspace_shortcut.py +++ b/frappe/desk/doctype/workspace_shortcut/workspace_shortcut.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/desk/form/assign_to.py b/frappe/desk/form/assign_to.py index 4107f95827..7853e807b8 100644 --- a/frappe/desk/form/assign_to.py +++ b/frappe/desk/form/assign_to.py @@ -217,7 +217,7 @@ def notify_assignment( # Search for email address in description -- i.e. assignee user_name = frappe.get_cached_value("User", frappe.session.user, "full_name") title = get_title(doc_type, doc_name) - description_html = "
{0}
".format(description) if description else None + description_html = f"
{description}
" if description else None if action == "CLOSE": subject = _("Your assignment on {0} {1} has been removed by {2}").format( diff --git a/frappe/desk/form/document_follow.py b/frappe/desk/form/document_follow.py index 527b9da036..86bd712926 100644 --- a/frappe/desk/form/document_follow.py +++ b/frappe/desk/form/document_follow.py @@ -192,9 +192,9 @@ def get_comments(doctype, doc_name, frequency, user): ) for comment in comments: if comment.comment_type == "Like": - by = """ By : {0}""".format(comment.modified_by) + by = f""" By : {comment.modified_by}""" elif comment.comment_type == "Comment": - by = """Commented by : {0}""".format(comment.modified_by) + by = f"""Commented by : {comment.modified_by}""" else: by = "" diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 7a53c8b65a..b60c11774f 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -4,7 +4,6 @@ import itertools import json from collections import defaultdict -from typing import Dict, List, Optional import frappe import frappe.desk.form.load @@ -15,7 +14,7 @@ from frappe.modules import load_doctype_module @frappe.whitelist() -def get_submitted_linked_docs(doctype: str, name: str) -> List[tuple]: +def get_submitted_linked_docs(doctype: str, name: str) -> list[tuple]: """Get all the nested submitted documents those are present in referencing tables (dependent tables). :param doctype: Document type @@ -134,14 +133,14 @@ class SubmittableDocumentTree: """limit doctype links to these doctypes.""" return list(set(self.get_submittable_doctypes()) - set(get_exempted_doctypes() or [])) - def get_submittable_doctypes(self) -> List[str]: + def get_submittable_doctypes(self) -> list[str]: """Returns list of submittable doctypes.""" if not self._submittable_doctypes: self._submittable_doctypes = frappe.db.get_all("DocType", {"is_submittable": 1}, pluck="name") return self._submittable_doctypes -def get_child_tables_of_doctypes(doctypes: List[str] = None): +def get_child_tables_of_doctypes(doctypes: list[str] = None): """Returns child tables by doctype.""" filters = [["fieldtype", "=", "Table"]] filters_for_docfield = filters @@ -174,8 +173,8 @@ def get_child_tables_of_doctypes(doctypes: List[str] = None): def get_references_across_doctypes( - to_doctypes: List[str] = None, limit_link_doctypes: List[str] = None -) -> List: + to_doctypes: list[str] = None, limit_link_doctypes: list[str] = None +) -> list: """Find doctype wise foreign key references. :param to_doctypes: Get links of these doctypes. @@ -213,7 +212,7 @@ def get_references_across_doctypes( def get_references_across_doctypes_by_link_field( - to_doctypes: List[str] = None, limit_link_doctypes: List[str] = None + to_doctypes: list[str] = None, limit_link_doctypes: list[str] = None ): """Find doctype wise foreign key references based on link fields. @@ -253,7 +252,7 @@ def get_references_across_doctypes_by_link_field( def get_references_across_doctypes_by_dynamic_link_field( - to_doctypes: List[str] = None, limit_link_doctypes: List[str] = None + to_doctypes: list[str] = None, limit_link_doctypes: list[str] = None ): """Find doctype wise foreign key references based on dynamic link fields. @@ -304,10 +303,10 @@ def get_references_across_doctypes_by_dynamic_link_field( def get_referencing_documents( reference_doctype: str, - reference_names: List[str], + reference_names: list[str], link_info: dict, get_parent_if_child_table_doc: bool = True, - parent_filters: List[list] = None, + parent_filters: list[list] = None, child_filters=None, allowed_parents=None, ): @@ -340,7 +339,7 @@ def get_referencing_documents( for parent, rows in itertools.groupby(res, key=lambda row: row["parenttype"]): if allowed_parents and parent not in allowed_parents: continue - filters = (parent_filters or []) + [["name", "in", tuple([row.parent for row in rows])]] + filters = (parent_filters or []) + [["name", "in", tuple(row.parent for row in rows)]] documents[parent].extend(frappe.db.get_all(parent, filters=filters, pluck="name") or []) return documents @@ -407,7 +406,7 @@ def get_exempted_doctypes(): @frappe.whitelist() -def get_linked_docs(doctype: str, name: str, linkinfo: Optional[Dict] = None) -> Dict[str, List]: +def get_linked_docs(doctype: str, name: str, linkinfo: dict | None = None) -> dict[str, list]: if isinstance(linkinfo, str): # additional fields are added in linkinfo linkinfo = json.loads(linkinfo) @@ -447,9 +446,7 @@ def get_linked_docs(doctype: str, name: str, linkinfo: Optional[Dict] = None) -> if link.get("add_fields"): fields += link["add_fields"] - fields = [ - "`tab{dt}`.`{fn}`".format(dt=dt, fn=sf.strip()) for sf in fields if sf and "`tab" not in sf - ] + fields = [f"`tab{dt}`.`{sf.strip()}`" for sf in fields if sf and "`tab" not in sf] try: if link.get("filters"): diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 5a6004652e..898c6461e9 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -2,7 +2,6 @@ # License: MIT. See LICENSE import json -from typing import List, Union from urllib.parse import quote import frappe @@ -34,25 +33,20 @@ def getdoc(doctype, name, user=None): if not frappe.db.exists(doctype, name): return [] - try: - doc = frappe.get_doc(doctype, name) - run_onload(doc) + doc = frappe.get_doc(doctype, name) + run_onload(doc) - if not doc.has_permission("read"): - frappe.flags.error_message = _("Insufficient Permission for {0}").format( - frappe.bold(doctype + " " + name) - ) - raise frappe.PermissionError(("read", doctype, name)) + if not doc.has_permission("read"): + frappe.flags.error_message = _("Insufficient Permission for {0}").format( + frappe.bold(doctype + " " + name) + ) + raise frappe.PermissionError(("read", doctype, name)) - doc.apply_fieldlevel_read_permissions() + doc.apply_fieldlevel_read_permissions() - # add file list - doc.add_viewed() - get_docinfo(doc) - - except Exception: - frappe.errprint(frappe.utils.get_traceback()) - raise + # add file list + doc.add_viewed() + get_docinfo(doc) doc.add_seen() set_link_titles(doc) @@ -218,8 +212,8 @@ def get_communications(doctype, name, start=0, limit=20): def get_comments( - doctype: str, name: str, comment_type: Union[str, List[str]] = "Comment" -) -> List[frappe._dict]: + doctype: str, name: str, comment_type: str | list[str] = "Comment" +) -> list[frappe._dict]: if isinstance(comment_type, list): comment_types = comment_type @@ -294,7 +288,7 @@ def get_communication_data( if after: # find after a particular date conditions += """ - AND C.creation > {0} + AND C.creation > {} """.format( after ) @@ -411,7 +405,7 @@ def get_document_email(doctype, name): return None email = email.split("@") - return "{0}+{1}+{2}@{3}".format(email[0], quote(doctype), quote(cstr(name)), email[1]) + return f"{email[0]}+{quote(doctype)}+{quote(cstr(name))}@{email[1]}" def get_automatic_email_link(): diff --git a/frappe/desk/form/meta.py b/frappe/desk/form/meta.py index dc26dfe5b0..5a426b4c63 100644 --- a/frappe/desk/form/meta.py +++ b/frappe/desk/form/meta.py @@ -52,7 +52,7 @@ def get_meta(doctype, cached=True): class FormMeta(Meta): def __init__(self, doctype): - super(FormMeta, self).__init__(doctype) + super().__init__(doctype) self.load_assets() def load_assets(self): @@ -74,7 +74,7 @@ class FormMeta(Meta): self.set("__assets_loaded", True) def as_dict(self, no_nulls=False): - d = super(FormMeta, self).as_dict(no_nulls=no_nulls) + d = super().as_dict(no_nulls=no_nulls) for k in ASSET_KEYS: d[k] = self.get(k) @@ -133,7 +133,7 @@ class FormMeta(Meta): templates = dict() for fname in os.listdir(path): if fname.endswith(".html"): - with io.open(os.path.join(path, fname), "r", encoding="utf-8") as f: + with open(os.path.join(path, fname), encoding="utf-8") as f: templates[fname.split(".")[0]] = scrub_html_template(f.read()) self.set("__templates", templates or None) diff --git a/frappe/desk/form/save.py b/frappe/desk/form/save.py index cc3865bc60..f3e7b6294f 100644 --- a/frappe/desk/form/save.py +++ b/frappe/desk/form/save.py @@ -10,42 +10,33 @@ from frappe.desk.form.load import run_onload @frappe.whitelist() def savedocs(doc, action): """save / submit / update doclist""" - try: - doc = frappe.get_doc(json.loads(doc)) - set_local_name(doc) + doc = frappe.get_doc(json.loads(doc)) + set_local_name(doc) - # action - doc.docstatus = {"Save": 0, "Submit": 1, "Update": 1, "Cancel": 2}[action] + # action + doc.docstatus = {"Save": 0, "Submit": 1, "Update": 1, "Cancel": 2}[action] - if doc.docstatus == 1: - doc.submit() - else: - doc.save() + if doc.docstatus == 1: + doc.submit() + else: + doc.save() - # update recent documents - run_onload(doc) - send_updated_docs(doc) + # update recent documents + run_onload(doc) + send_updated_docs(doc) - frappe.msgprint(frappe._("Saved"), indicator="green", alert=True) - except Exception: - frappe.errprint(frappe.utils.get_traceback()) - raise + frappe.msgprint(frappe._("Saved"), indicator="green", alert=True) @frappe.whitelist() def cancel(doctype=None, name=None, workflow_state_fieldname=None, workflow_state=None): """cancel a doclist""" - try: - doc = frappe.get_doc(doctype, name) - if workflow_state_fieldname and workflow_state: - doc.set(workflow_state_fieldname, workflow_state) - doc.cancel() - send_updated_docs(doc) - frappe.msgprint(frappe._("Cancelled"), indicator="red", alert=True) - - except Exception: - frappe.errprint(frappe.utils.get_traceback()) - raise + doc = frappe.get_doc(doctype, name) + if workflow_state_fieldname and workflow_state: + doc.set(workflow_state_fieldname, workflow_state) + doc.cancel() + send_updated_docs(doc) + frappe.msgprint(frappe._("Cancelled"), indicator="red", alert=True) def send_updated_docs(doc): diff --git a/frappe/desk/form/utils.py b/frappe/desk/form/utils.py index 573ec17979..9e10ced912 100644 --- a/frappe/desk/form/utils.py +++ b/frappe/desk/form/utils.py @@ -85,7 +85,7 @@ def get_next(doctype, value, prev, filters=None, sort_order="desc", sort_field=" doctype, fields=["name"], filters=filters, - order_by="`tab{0}`.{1}".format(doctype, sort_field) + " " + sort_order, + order_by=f"`tab{doctype}`.{sort_field}" + " " + sort_order, limit_start=0, limit_page_length=1, as_list=True, diff --git a/frappe/desk/like.py b/frappe/desk/like.py index 9e97cb269c..0f297455e7 100644 --- a/frappe/desk/like.py +++ b/frappe/desk/like.py @@ -90,7 +90,7 @@ def add_comment(doctype, name): link = get_link_to_form( doc.reference_doctype, doc.reference_name, - "{0} {1}".format(_(doc.reference_doctype), doc.reference_name), + f"{_(doc.reference_doctype)} {doc.reference_name}", ) doc.add_comment( diff --git a/frappe/desk/listview.py b/frappe/desk/listview.py index 5149f8bf86..d48a7f3de4 100644 --- a/frappe/desk/listview.py +++ b/frappe/desk/listview.py @@ -1,6 +1,5 @@ # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE -from typing import Dict, List import frappe from frappe.query_builder import Order @@ -30,7 +29,7 @@ def set_list_settings(doctype, values): @frappe.whitelist() -def get_group_by_count(doctype: str, current_filters: str, field: str) -> List[Dict]: +def get_group_by_count(doctype: str, current_filters: str, field: str) -> list[dict]: current_filters = frappe.parse_json(current_filters) if field == "assigned_to": diff --git a/frappe/desk/moduleview.py b/frappe/desk/moduleview.py index a4fc2ccd1e..913b3406e3 100644 --- a/frappe/desk/moduleview.py +++ b/frappe/desk/moduleview.py @@ -253,13 +253,13 @@ def apply_permissions(data): def get_disabled_reports(): if not hasattr(frappe.local, "disabled_reports"): - frappe.local.disabled_reports = set(r.name for r in frappe.get_all("Report", {"disabled": 1})) + frappe.local.disabled_reports = {r.name for r in frappe.get_all("Report", {"disabled": 1})} return frappe.local.disabled_reports def get_config(app, module): """Load module info from `[app].config.[module]`.""" - config = frappe.get_module("{app}.config.{module}".format(app=app, module=module)) + config = frappe.get_module(f"{app}.config.{module}") config = config.get_data() sections = [s for s in config if s.get("condition", True)] @@ -283,7 +283,7 @@ def get_config(app, module): def config_exists(app, module): try: - frappe.get_module("{app}.config.{module}".format(app=app, module=module)) + frappe.get_module(f"{app}.config.{module}") return True except ImportError: return False diff --git a/frappe/desk/page/activity/__init__.py b/frappe/desk/page/activity/__init__.py index 8b13789179..e69de29bb2 100644 --- a/frappe/desk/page/activity/__init__.py +++ b/frappe/desk/page/activity/__init__.py @@ -1 +0,0 @@ - diff --git a/frappe/desk/page/backups/backups.py b/frappe/desk/page/backups/backups.py index ec5bea3c4b..2ef09df900 100644 --- a/frappe/desk/page/backups/backups.py +++ b/frappe/desk/page/backups/backups.py @@ -21,9 +21,9 @@ def get_context(context): def get_size(path): size = os.path.getsize(path) if size > 1048576: - return "{0:.1f}M".format(float(size) / 1048576) + return f"{float(size) / 1048576:.1f}M" else: - return "{0:.1f}K".format(float(size) / 1024) + return f"{float(size) / 1024:.1f}K" path = get_site_path("private", "backups") files = [x for x in os.listdir(path) if os.path.isfile(os.path.join(path, x))] diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py index 8fc4b3f694..3422602720 100755 --- a/frappe/desk/page/setup_wizard/setup_wizard.py +++ b/frappe/desk/page/setup_wizard/setup_wizard.py @@ -339,11 +339,11 @@ def prettify_args(args): if isinstance(val, str) and "data:image" in val: filename = val.split("data:image", 1)[0].strip(", ") size = round((len(val) * 3 / 4) / 1048576.0, 2) - args[key] = "Image Attached: '{0}' of size {1} MB".format(filename, size) + args[key] = f"Image Attached: '{filename}' of size {size} MB" pretty_args = [] for key in sorted(args): - pretty_args.append("{} = {}".format(key, args[key])) + pretty_args.append(f"{key} = {args[key]}") return pretty_args @@ -386,7 +386,7 @@ def email_setup_wizard_exception(traceback, args): frappe.sendmail( recipients=frappe.conf.setup_wizard_exception_email, sender=frappe.session.user, - subject="Setup failed: {}".format(frappe.local.site), + subject=f"Setup failed: {frappe.local.site}", message=message, delayed=False, ) diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index a51fd8b1e3..29c8ed08d3 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -187,7 +187,7 @@ def get_script(report_name): script = None if os.path.exists(script_path): - with open(script_path, "r") as f: + with open(script_path) as f: script = f.read() script += f"\n\n//# sourceURL={scrub(report.name)}.js" diff --git a/frappe/desk/report/todo/todo.py b/frappe/desk/report/todo/todo.py index 7c566c74ea..e75b8d1900 100644 --- a/frappe/desk/report/todo/todo.py +++ b/frappe/desk/report/todo/todo.py @@ -46,7 +46,7 @@ def execute(filters=None): for todo in todo_list: if todo.owner == frappe.session.user or todo.assigned_by == frappe.session.user: if todo.reference_type: - todo.reference = """%s: %s""" % ( + todo.reference = """{}: {}""".format( todo.reference_type, todo.reference_name, todo.reference_type, diff --git a/frappe/desk/report_dump.py b/frappe/desk/report_dump.py index ac01cf892f..6650d24757 100644 --- a/frappe/desk/report_dump.py +++ b/frappe/desk/report_dump.py @@ -53,7 +53,7 @@ def get_data(doctypes, last_modified): out[dt]["data"] = [ list(t) for t in frappe.db.sql( - """select %s from %s %s %s""" % (",".join(args["columns"]), table, conditions, order_by) + """select {} from {} {} {}""".format(",".join(args["columns"]), table, conditions, order_by) ) ] diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index c7295730de..edb646d077 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -167,7 +167,7 @@ def setup_group_by(data): def raise_invalid_field(fieldname): - frappe.throw(_("Field not permitted in query") + ": {0}".format(fieldname), frappe.DataError) + frappe.throw(_("Field not permitted in query") + f": {fieldname}", frappe.DataError) def is_standard(fieldname): diff --git a/frappe/desk/search.py b/frappe/desk/search.py index eb1a2e82ba..8ae635093c 100644 --- a/frappe/desk/search.py +++ b/frappe/desk/search.py @@ -34,7 +34,7 @@ def sanitize_searchfield(searchfield): _raise_exception(searchfield) # to avoid and, or and like - elif any(" {0} ".format(keyword) in searchfield.split() for keyword in blacklisted_keywords): + elif any(f" {keyword} " in searchfield.split() for keyword in blacklisted_keywords): _raise_exception(searchfield) # to avoid select, delete, drop, update and case @@ -166,7 +166,7 @@ def search_widget( in ["Data", "Text", "Small Text", "Long Text", "Link", "Select", "Read Only", "Text Editor"] ) ): - or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)]) + or_filters.append([doctype, f.strip(), "like", f"%{txt}%"]) if meta.get("fields", {"fieldname": "enabled", "fieldtype": "Check"}): filters.append([doctype, "enabled", "=", 1]) @@ -177,7 +177,7 @@ def search_widget( fields = get_std_fields_list(meta, searchfield or "name") if filter_fields: fields = list(set(fields + json.loads(filter_fields))) - formatted_fields = ["`tab%s`.`%s`" % (meta.name, f.strip()) for f in fields] + formatted_fields = [f"`tab{meta.name}`.`{f.strip()}`" for f in fields] title_field_query = get_title_field_query(meta) @@ -197,7 +197,7 @@ def search_widget( order_by_based_on_meta = get_order_by(doctype, meta) # 2 is the index of _relevance column - order_by = "_relevance, {0}, `tab{1}`.idx desc".format(order_by_based_on_meta, doctype) + order_by = f"_relevance, {order_by_based_on_meta}, `tab{doctype}`.idx desc" ptype = "select" if frappe.only_has_select_perm(doctype) else "read" ignore_permissions = ( @@ -270,7 +270,7 @@ def get_title_field_query(meta): field = None if title_field and show_title_field_in_link: - field = "`tab{0}`.{1} as `label`".format(meta.name, title_field) + field = f"`tab{meta.name}`.{title_field} as `label`" return field diff --git a/frappe/desk/treeview.py b/frappe/desk/treeview.py index d7a8db8792..f8b2a67c82 100644 --- a/frappe/desk/treeview.py +++ b/frappe/desk/treeview.py @@ -43,7 +43,7 @@ def get_children(doctype, parent="", **filters): def _get_children(doctype, parent="", ignore_permissions=False): parent_field = "parent_" + doctype.lower().replace(" ", "_") - filters = [["ifnull(`{0}`,'')".format(parent_field), "=", parent], ["docstatus", "<", 2]] + filters = [[f"ifnull(`{parent_field}`,'')", "=", parent], ["docstatus", "<", 2]] meta = frappe.get_meta(doctype) @@ -51,7 +51,7 @@ def _get_children(doctype, parent="", ignore_permissions=False): doctype, fields=[ "name as value", - "{0} as title".format(meta.get("title_field") or "name"), + "{} as title".format(meta.get("title_field") or "name"), "is_group as expandable", ], filters=filters, diff --git a/frappe/email/__init__.py b/frappe/email/__init__.py index 51917cc7af..1f6af4a3e7 100644 --- a/frappe/email/__init__.py +++ b/frappe/email/__init__.py @@ -1,8 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE -from typing import Dict, List - import frappe from frappe.desk.reportview import build_match_conditions @@ -12,7 +10,7 @@ def sendmail_to_system_managers(subject, content): @frappe.whitelist() -def get_contact_list(txt, page_length=20) -> List[Dict]: +def get_contact_list(txt, page_length=20) -> list[dict]: """Returns contacts (from autosuggest)""" if cached_contacts := get_cached_contacts(txt): 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 9f897a1308..b9b5e4e8d7 100644 --- a/frappe/email/doctype/auto_email_report/auto_email_report.py +++ b/frappe/email/doctype/auto_email_report/auto_email_report.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -165,7 +164,7 @@ class AutoEmailReport(Document): ) def get_file_name(self): - return "{0}.{1}".format(self.report.replace(" ", "-").replace("/", "-"), self.format.lower()) + return "{}.{}".format(self.report.replace(" ", "-").replace("/", "-"), self.format.lower()) def prepare_dynamic_filters(self): self.filters = frappe.parse_json(self.filters) @@ -260,9 +259,7 @@ def send_daily(): try: auto_email_report.send() except Exception as e: - auto_email_report.log_error( - "Failed to send {0} Auto Email Report".format(auto_email_report.name) - ) + auto_email_report.log_error(f"Failed to send {auto_email_report.name} Auto Email Report") def send_monthly(): diff --git a/frappe/email/doctype/auto_email_report/test_auto_email_report.py b/frappe/email/doctype/auto_email_report/test_auto_email_report.py index aa8dffb9e0..ee0a363bd9 100644 --- a/frappe/email/doctype/auto_email_report/test_auto_email_report.py +++ b/frappe/email/doctype/auto_email_report/test_auto_email_report.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import json diff --git a/frappe/email/doctype/document_follow/document_follow.py b/frappe/email/doctype/document_follow/document_follow.py index 3b7d411fb5..6f9d63f3be 100644 --- a/frappe/email/doctype/document_follow/document_follow.py +++ b/frappe/email/doctype/document_follow/document_follow.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/document_follow/test_document_follow.py b/frappe/email/doctype/document_follow/test_document_follow.py index 1f31338351..159a399ee8 100644 --- a/frappe/email/doctype/document_follow/test_document_follow.py +++ b/frappe/email/doctype/document_follow/test_document_follow.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index a89b9a2747..02afe4f4b5 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -8,7 +8,6 @@ import socket import time from datetime import datetime, timedelta from poplib import error_proto -from typing import List import frappe from frappe import _, are_emails_muted, safe_encode @@ -259,7 +258,7 @@ class EmailAccount(Document): else: frappe.throw(cstr(e)) - except socket.error: + except OSError: if in_receive: # timeout while connecting, see receive.py connect method description = frappe.message_log.pop() if frappe.message_log else "Socket Error" @@ -444,10 +443,10 @@ class EmailAccount(Document): frappe.cache().set_value("workers:no-internet", True) def set_failed_attempts_count(self, value): - frappe.cache().set("{0}:email-account-failed-attempts".format(self.name), value) + frappe.cache().set(f"{self.name}:email-account-failed-attempts", value) def get_failed_attempts_count(self): - return cint(frappe.cache().get("{0}:email-account-failed-attempts".format(self.name))) + return cint(frappe.cache().get(f"{self.name}:email-account-failed-attempts")) def receive(self): """Called by scheduler to receive emails from this EMail account using POP3/IMAP.""" @@ -485,7 +484,7 @@ class EmailAccount(Document): if exceptions: raise Exception(frappe.as_json(exceptions)) - def get_inbound_mails(self) -> List[InboundMail]: + def get_inbound_mails(self) -> list[InboundMail]: """retrive and return inbound mails.""" mails = [] @@ -595,7 +594,7 @@ class EmailAccount(Document): if self.email_sync_option == "ALL": max_uid = get_max_email_uid(self.name) last_uid = max_uid + int(self.initial_sync_count or 100) if max_uid == 1 else "*" - return "UID {}:{}".format(max_uid, last_uid) + return f"UID {max_uid}:{last_uid}" else: return self.email_sync_option or "UNSEEN" @@ -786,7 +785,7 @@ def pull(now=False): else: # job_name is used to prevent duplicates in queue - job_name = "pull_from_email_account|{0}".format(email_account.name) + job_name = f"pull_from_email_account|{email_account.name}" if job_name not in queued_jobs: enqueue( diff --git a/frappe/email/doctype/email_account/test_email_account.py b/frappe/email/doctype/email_account/test_email_account.py index 537bf9eb7f..9ab004cdd0 100644 --- a/frappe/email/doctype/email_account/test_email_account.py +++ b/frappe/email/doctype/email_account/test_email_account.py @@ -39,7 +39,7 @@ class TestEmailAccount(unittest.TestCase): frappe.db.delete("Unhandled Email") def get_test_mail(self, fname): - with open(os.path.join(os.path.dirname(__file__), "test_mails", fname), "r") as f: + with open(os.path.join(os.path.dirname(__file__), "test_mails", fname)) as f: return f.read() def test_incoming(self): @@ -211,7 +211,7 @@ class TestEmailAccount(unittest.TestCase): sent_mail = email.message_from_string(frappe.get_last_doc("Email Queue").message) - with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-1.raw"), "r") as f: + with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-1.raw")) as f: raw = f.read() raw = raw.replace("<-- in-reply-to -->", sent_mail.get("Message-Id")) @@ -233,10 +233,10 @@ class TestEmailAccount(unittest.TestCase): def test_threading_by_subject(self): cleanup(["in", ["test_sender@example.com", "test@example.com"]]) - with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-2.raw"), "r") as f: + with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-2.raw")) as f: test_mails = [f.read()] - with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-3.raw"), "r") as f: + with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-3.raw")) as f: test_mails.append(f.read()) # parse reply @@ -280,7 +280,7 @@ class TestEmailAccount(unittest.TestCase): last_mail = frappe.get_doc("Email Queue", dict(reference_name=event.name)) # get test mail with message-id as in-reply-to - with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-4.raw"), "r") as f: + with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-4.raw")) as f: messages = { # append_to = ToDo '"INBOX"': { @@ -451,7 +451,7 @@ class TestInboundMail(unittest.TestCase): frappe.db.delete("ToDo") def get_test_mail(self, fname): - with open(os.path.join(os.path.dirname(__file__), "test_mails", fname), "r") as f: + with open(os.path.join(os.path.dirname(__file__), "test_mails", fname)) as f: return f.read() def new_doc(self, doctype, **data): diff --git a/frappe/email/doctype/email_domain/email_domain.py b/frappe/email/doctype/email_domain/email_domain.py index ff59725fd7..ab6546e4e6 100644 --- a/frappe/email/doctype/email_domain/email_domain.py +++ b/frappe/email/doctype/email_domain/email_domain.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE @@ -53,12 +52,10 @@ class EmailDomain(Document): test = poplib.POP3(self.email_server, port=get_port(self)) except Exception as e: - logger.warn( - 'Incoming email account "{host}" not correct'.format(host=self.email_server), exc_info=e - ) + logger.warn(f'Incoming email account "{self.email_server}" not correct', exc_info=e) frappe.throw( title=_("Incoming email account not correct"), - msg='Error connecting IMAP/POP3 "{host}": {e}'.format(host=self.email_server, e=e), + msg=f'Error connecting IMAP/POP3 "{self.email_server}": {e}', ) finally: @@ -94,12 +91,10 @@ class EmailDomain(Document): sess = smtplib.SMTP(cstr(self.smtp_server or ""), cint(self.smtp_port) or None) sess.quit() except Exception as e: - logger.warn( - 'Outgoing email account "{host}" not correct'.format(host=self.smtp_server), exc_info=e - ) + logger.warn(f'Outgoing email account "{self.smtp_server}" not correct', exc_info=e) frappe.throw( title=_("Outgoing email account not correct"), - msg='Error connecting SMTP "{host}": {e}'.format(host=self.smtp_server, e=e), + msg=f'Error connecting SMTP "{self.smtp_server}": {e}', ) def on_update(self): diff --git a/frappe/email/doctype/email_domain/test_email_domain.py b/frappe/email/doctype/email_domain/test_email_domain.py index 0162e4efe0..55a8d620a8 100644 --- a/frappe/email/doctype/email_domain/test_email_domain.py +++ b/frappe/email/doctype/email_domain/test_email_domain.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/email_flag_queue/email_flag_queue.py b/frappe/email/doctype/email_flag_queue/email_flag_queue.py index b7ca48faf0..cf28ce0628 100644 --- a/frappe/email/doctype/email_flag_queue/email_flag_queue.py +++ b/frappe/email/doctype/email_flag_queue/email_flag_queue.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/email_flag_queue/test_email_flag_queue.py b/frappe/email/doctype/email_flag_queue/test_email_flag_queue.py index 11571da7d9..8bfc9230a4 100644 --- a/frappe/email/doctype/email_flag_queue/test_email_flag_queue.py +++ b/frappe/email/doctype/email_flag_queue/test_email_flag_queue.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/email_group/email_group.py b/frappe/email/doctype/email_group/email_group.py index 6489e82341..ea62a6e9ec 100755 --- a/frappe/email/doctype/email_group/email_group.py +++ b/frappe/email/doctype/email_group/email_group.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -12,7 +11,7 @@ class EmailGroup(Document): def onload(self): singles = [d.name for d in frappe.db.get_all("DocType", "name", {"issingle": 1})] self.get("__onload").import_types = [ - {"value": d.parent, "label": "{0} ({1})".format(d.parent, d.label)} + {"value": d.parent, "label": f"{d.parent} ({d.label})"} for d in frappe.db.get_all("DocField", ("parent", "label"), {"options": "Email"}) if d.parent not in singles ] diff --git a/frappe/email/doctype/email_group/test_email_group.py b/frappe/email/doctype/email_group/test_email_group.py index 96032d35cc..aa41285f90 100644 --- a/frappe/email/doctype/email_group/test_email_group.py +++ b/frappe/email/doctype/email_group/test_email_group.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/email_group_member/email_group_member.py b/frappe/email/doctype/email_group_member/email_group_member.py index 76990b18fb..c0995d393b 100644 --- a/frappe/email/doctype/email_group_member/email_group_member.py +++ b/frappe/email/doctype/email_group_member/email_group_member.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/email_group_member/test_email_group_member.py b/frappe/email/doctype/email_group_member/test_email_group_member.py index ae608a4e15..749792fe52 100644 --- a/frappe/email/doctype/email_group_member/test_email_group_member.py +++ b/frappe/email/doctype/email_group_member/test_email_group_member.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index c51446947c..7b57adf6fb 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -156,7 +155,7 @@ class EmailQueue(Document): ( frappe.qb.from_(email_queue) .delete() - .where((email_queue.modified < (Now() - Interval(days=days)))) + .where(email_queue.modified < (Now() - Interval(days=days))) ).run() # delete child tables, note that this has potential to leave some orphan @@ -165,7 +164,7 @@ class EmailQueue(Document): ( frappe.qb.from_(email_recipient) .delete() - .where((email_recipient.modified < (Now() - Interval(days=days)))) + .where(email_recipient.modified < (Now() - Interval(days=days))) ).run() @@ -244,7 +243,7 @@ class SendMailContext: self.sent_to.append(recipient.recipient) def is_mail_sent_to_all(self): - return sorted(self.sent_to) == sorted([rec.recipient for rec in self.queue_doc.recipients]) + return sorted(self.sent_to) == sorted(rec.recipient for rec in self.queue_doc.recipients) def get_message_object(self, message): return Parser(policy=SMTPUTF8).parsestr(message) @@ -660,7 +659,7 @@ class QueueBuilder: # bad Email Address - don't add to queue frappe.log_error( title="Invalid email address", - message="Invalid email address Sender: {0}, Recipients: {1}, \nTraceback: {2} ".format( + message="Invalid email address Sender: {}, Recipients: {}, \nTraceback: {} ".format( self.sender, ", ".join(self.final_recipients()), traceback.format_exc() ), reference_doctype=self.reference_doctype, diff --git a/frappe/email/doctype/email_queue/test_email_queue.py b/frappe/email/doctype/email_queue/test_email_queue.py index 435e4e691f..5a608b1b23 100644 --- a/frappe/email/doctype/email_queue/test_email_queue.py +++ b/frappe/email/doctype/email_queue/test_email_queue.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/email_queue_recipient/email_queue_recipient.py b/frappe/email/doctype/email_queue_recipient/email_queue_recipient.py index d2e4753ddf..bcb8d9b05d 100644 --- a/frappe/email/doctype/email_queue_recipient/email_queue_recipient.py +++ b/frappe/email/doctype/email_queue_recipient/email_queue_recipient.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/email_rule/email_rule.py b/frappe/email/doctype/email_rule/email_rule.py index 5075024b73..ab04632280 100644 --- a/frappe/email/doctype/email_rule/email_rule.py +++ b/frappe/email/doctype/email_rule/email_rule.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/email_rule/test_email_rule.py b/frappe/email/doctype/email_rule/test_email_rule.py index 7b7a9a5c23..1da5d34d6b 100644 --- a/frappe/email/doctype/email_rule/test_email_rule.py +++ b/frappe/email/doctype/email_rule/test_email_rule.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/email_template/test_email_template.py b/frappe/email/doctype/email_template/test_email_template.py index d37b5497fb..291f7e1df0 100644 --- a/frappe/email/doctype/email_template/test_email_template.py +++ b/frappe/email/doctype/email_template/test_email_template.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py index 131546a3c2..c9ab17d61d 100644 --- a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py +++ b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/email_unsubscribe/test_email_unsubscribe.py b/frappe/email/doctype/email_unsubscribe/test_email_unsubscribe.py index 0133c6c4b5..9ba99a6690 100644 --- a/frappe/email/doctype/email_unsubscribe/test_email_unsubscribe.py +++ b/frappe/email/doctype/email_unsubscribe/test_email_unsubscribe.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/newsletter/newsletter.py b/frappe/email/doctype/newsletter/newsletter.py index 6fcdce482f..757a8c875b 100644 --- a/frappe/email/doctype/newsletter/newsletter.py +++ b/frappe/email/doctype/newsletter/newsletter.py @@ -1,7 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See LICENSE -from typing import Dict, List import frappe import frappe.utils @@ -21,7 +20,7 @@ class Newsletter(WebsiteGenerator): self.validate_publishing() @property - def newsletter_recipients(self) -> List[str]: + def newsletter_recipients(self) -> list[str]: if getattr(self, "_recipients", None) is None: self._recipients = self.get_recipients() return self._recipients @@ -112,7 +111,7 @@ class Newsletter(WebsiteGenerator): if self.send_webview_link and not self.published: frappe.throw(_("Newsletter must be published to send webview link in email")) - def get_linked_email_queue(self) -> List[str]: + def get_linked_email_queue(self) -> list[str]: """Get list of email queue linked to this newsletter.""" return frappe.get_all( "Email Queue", @@ -123,7 +122,7 @@ class Newsletter(WebsiteGenerator): pluck="name", ) - def get_success_recipients(self) -> List[str]: + def get_success_recipients(self) -> list[str]: """Recipients who have already received the newsletter. Couldn't think of a better name ;) @@ -137,7 +136,7 @@ class Newsletter(WebsiteGenerator): pluck="recipient", ) - def get_pending_recipients(self) -> List[str]: + def get_pending_recipients(self) -> list[str]: """Get list of pending recipients of the newsletter. These recipients may not have receive the newsletter in the previous iteration. """ @@ -156,11 +155,11 @@ class Newsletter(WebsiteGenerator): self.total_recipients = len(recipients) self.save() - def get_newsletter_attachments(self) -> List[Dict[str, str]]: + def get_newsletter_attachments(self) -> list[dict[str, str]]: """Get list of attachments on current Newsletter""" return [{"file_url": row.attachment} for row in self.attachments] - def send_newsletter(self, emails: List[str]): + def send_newsletter(self, emails: list[str]): """Trigger email generation for `emails` and add it in Email Queue.""" attachments = self.get_newsletter_attachments() sender = self.send_from or frappe.utils.get_formatted_email(self.owner) @@ -197,7 +196,7 @@ class Newsletter(WebsiteGenerator): return frappe.render_template(message, {"doc": self.as_dict()}) - def get_recipients(self) -> List[str]: + def get_recipients(self) -> list[str]: """Get recipients from Email Group""" emails = frappe.get_all( "Email Group Member", @@ -206,7 +205,7 @@ class Newsletter(WebsiteGenerator): ) return list(set(emails)) - def get_email_groups(self) -> List[str]: + def get_email_groups(self) -> list[str]: # wondering why the 'or'? i can't figure out why both aren't equivalent - @gavin return [x.email_group for x in self.email_group] or frappe.get_all( "Newsletter Email Group", @@ -214,7 +213,7 @@ class Newsletter(WebsiteGenerator): pluck="email_group", ) - def get_attachments(self) -> List[Dict[str, str]]: + def get_attachments(self) -> list[dict[str, str]]: return frappe.get_all( "File", fields=["name", "file_name", "file_url", "is_private"], @@ -267,8 +266,8 @@ def subscribe(email, email_group=_("Website")): # noqa _("Click here to verify"), ) content = """ -

{0}. {1}.

-

{3}

+

{}. {}.

+

{}

""".format( *translatable_content ) diff --git a/frappe/email/doctype/newsletter/test_newsletter.py b/frappe/email/doctype/newsletter/test_newsletter.py index 550ee8164b..524289db7f 100644 --- a/frappe/email/doctype/newsletter/test_newsletter.py +++ b/frappe/email/doctype/newsletter/test_newsletter.py @@ -2,7 +2,6 @@ # MIT License. See LICENSE from random import choice -from typing import Union from unittest.mock import MagicMock, PropertyMock, patch import frappe @@ -79,7 +78,7 @@ class TestNewsletterMixin: frappe.db.release_savepoint(savepoint) - def send_newsletter(self, published=0, schedule_send=None) -> Union[str, None]: + def send_newsletter(self, published=0, schedule_send=None) -> str | None: frappe.db.delete("Email Queue") frappe.db.delete("Email Queue Recipient") frappe.db.delete("Newsletter") diff --git a/frappe/email/doctype/newsletter_email_group/newsletter_email_group.py b/frappe/email/doctype/newsletter_email_group/newsletter_email_group.py index 9fe1364d11..41ada8a491 100644 --- a/frappe/email/doctype/newsletter_email_group/newsletter_email_group.py +++ b/frappe/email/doctype/newsletter_email_group/newsletter_email_group.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index c8079f94e8..8d0857ac60 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -13,7 +12,7 @@ from frappe.desk.doctype.notification_log.notification_log import enqueue_create from frappe.integrations.doctype.slack_webhook_url.slack_webhook_url import send_slack_message from frappe.model.document import Document from frappe.modules.utils import export_module_json, get_doc_module -from frappe.utils import add_to_date, is_html, nowdate, parse_val, validate_email_address +from frappe.utils import add_to_date, cast, is_html, nowdate, validate_email_address from frappe.utils.jinja import validate_template from frappe.utils.safe_exec import get_safe_globals @@ -368,7 +367,7 @@ def get_context(context): template = "" template_path = os.path.join(os.path.dirname(module.__file__), frappe.scrub(self.name) + extn) if os.path.exists(template_path): - with open(template_path, "r") as f: + with open(template_path) as f: template = f.read() return template @@ -417,7 +416,7 @@ def trigger_notifications(doc, method=None): frappe.db.commit() -def evaluate_alert(doc, alert, event): +def evaluate_alert(doc: Document, alert, event): from jinja2 import TemplateError try: @@ -433,14 +432,14 @@ def evaluate_alert(doc, alert, event): if event == "Value Change" and not doc.is_new(): if not frappe.db.has_column(doc.doctype, alert.value_changed): alert.db_set("enabled", 0) - alert.log_error("Notification {0} has been disabled due to missing field".format(alert.name)) + alert.log_error(f"Notification {alert.name} has been disabled due to missing field") return doc_before_save = doc.get_doc_before_save() field_value_before_save = doc_before_save.get(alert.value_changed) if doc_before_save else None - field_value_before_save = parse_val(field_value_before_save) - if doc.get(alert.value_changed) == field_value_before_save: + fieldtype = doc.meta.get_field(alert.value_changed).fieldtype + if cast(fieldtype, doc.get(alert.value_changed)) == cast(fieldtype, field_value_before_save): # value not changed return diff --git a/frappe/email/doctype/notification/test_notification.py b/frappe/email/doctype/notification/test_notification.py index 039b6db2f0..0f570b1fd3 100644 --- a/frappe/email/doctype/notification/test_notification.py +++ b/frappe/email/doctype/notification/test_notification.py @@ -1,7 +1,7 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest +from contextlib import contextmanager import frappe import frappe.utils @@ -11,6 +11,15 @@ from frappe.desk.form import assign_to test_dependencies = ["User", "Notification"] +@contextmanager +def get_test_notification(config): + try: + notification = frappe.get_doc(doctype="Notification", **config).insert() + yield notification + finally: + notification.delete() + + class TestNotification(unittest.TestCase): def setUp(self): frappe.db.delete("Email Queue") @@ -344,6 +353,31 @@ class TestNotification(unittest.TestCase): self.assertTrue("test2@example.com" in recipients) self.assertTrue("test1@example.com" in recipients) + def test_notification_value_change_casted_types(self): + """Make sure value change event dont fire because of incorrect type comparisons.""" + frappe.set_user("Administrator") + + notification = { + "document_type": "User", + "subject": "User changed birthdate", + "event": "Value Change", + "channel": "System Notification", + "value_changed": "birth_date", + "recipients": [{"receiver_by_document_field": "email"}], + } + + with get_test_notification(notification) as n: + frappe.db.delete("Notification Log", {"subject": n.subject}) + + user = frappe.get_doc("User", "test@example.com") + user.birth_date = frappe.utils.add_days(user.birth_date, 1) + user.save() + + user.reload() + user.birth_date = frappe.utils.getdate(user.birth_date) + user.save() + self.assertEqual(1, frappe.db.count("Notification Log", {"subject": n.subject})) + @classmethod def tearDownClass(cls): frappe.delete_doc_if_exists("Notification", "ToDo Status Update") diff --git a/frappe/email/doctype/notification_recipient/notification_recipient.py b/frappe/email/doctype/notification_recipient/notification_recipient.py index 1785590e93..75bb274599 100644 --- a/frappe/email/doctype/notification_recipient/notification_recipient.py +++ b/frappe/email/doctype/notification_recipient/notification_recipient.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/email/doctype/unhandled_email/test_unhandled_email.py b/frappe/email/doctype/unhandled_email/test_unhandled_email.py index 1485f3bbaa..debc52d685 100644 --- a/frappe/email/doctype/unhandled_email/test_unhandled_email.py +++ b/frappe/email/doctype/unhandled_email/test_unhandled_email.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/email/doctype/unhandled_email/unhandled_email.py b/frappe/email/doctype/unhandled_email/unhandled_email.py index e703f1ec97..1c315e2423 100644 --- a/frappe/email/doctype/unhandled_email/unhandled_email.py +++ b/frappe/email/doctype/unhandled_email/unhandled_email.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index 3a952e1487..3288ca2148 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -7,7 +7,6 @@ import re from email import policy from email.header import Header from email.mime.multipart import MIMEMultipart -from typing import Optional import frappe from frappe.email.doctype.email_account.email_account import EmailAccount @@ -354,7 +353,7 @@ def get_formatted_html( print_html=None, email_account=None, header=None, - unsubscribe_link: Optional[frappe._dict] = None, + unsubscribe_link: frappe._dict | None = None, sender=None, with_container=False, ): @@ -454,7 +453,7 @@ def add_attachment(fname, fcontent, content_type=None, parent=None, content_id=N attachment_type = "inline" if inline else "attachment" part.add_header("Content-Disposition", attachment_type, filename=str(fname)) if content_id: - part.add_header("Content-ID", "<{0}>".format(content_id)) + part.add_header("Content-ID", f"<{content_id}>") parent.attach(part) diff --git a/frappe/email/receive.py b/frappe/email/receive.py index dd8273d778..93e1a68285 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -269,7 +269,7 @@ class EmailServer: 1 if uidnext < (sync_count + 1) or (uidnext - sync_count) < 1 else uidnext - sync_count ) # sync last 100 email - self.settings.email_sync_rule = "UID {}:{}".format(from_uid, uidnext) + self.settings.email_sync_rule = f"UID {from_uid}:{uidnext}" self.uid_reindexed = True elif uid_validity == current_uid_validity: @@ -534,10 +534,10 @@ class Email: for key in ("From", "To", "Subject", "Date"): value = cstr(message.get(key)) if value: - headers.append("{label}: {value}".format(label=_(key), value=escape(value))) + headers.append(f"{_(key)}: {escape(value)}") self.text_content += "\n".join(headers) - self.html_content += "
" + "\n".join("

{0}

".format(h) for h in headers) + self.html_content += "
" + "\n".join(f"

{h}

" for h in headers) if not message.is_multipart() and message.get_content_type() == "text/plain": # email.parser didn't parse it! @@ -710,7 +710,7 @@ class InboundMail(Email): content = self.content for file in attachments: if file.name in self.cid_map and self.cid_map[file.name]: - content = content.replace("cid:{0}".format(self.cid_map[file.name]), file.file_url) + content = content.replace(f"cid:{self.cid_map[file.name]}", file.file_url) return content def is_notification(self): @@ -895,7 +895,7 @@ class InboundMail(Email): users = frappe.get_all( "User Email", filters={"email_account": email_account.name}, fields=["parent"] ) - return list(set([user.get("parent") for user in users])) + return list({user.get("parent") for user in users}) @staticmethod def clean_subject(subject): @@ -946,7 +946,7 @@ class InboundMail(Email): } -class TimerMixin(object): +class TimerMixin: def __init__(self, *args, **kwargs): self.timeout = kwargs.pop("timeout", 0.0) self.elapsed_time = 0.0 diff --git a/frappe/email/test_email_body.py b/frappe/email/test_email_body.py index 3de21f64ce..9f76ec6a59 100644 --- a/frappe/email/test_email_body.py +++ b/frappe/email/test_email_body.py @@ -128,7 +128,7 @@ w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> processed_message = """
- test + test
""".format( diff --git a/frappe/event_streaming/doctype/document_type_field_mapping/document_type_field_mapping.py b/frappe/event_streaming/doctype/document_type_field_mapping/document_type_field_mapping.py index 3019d70035..96d9e0fcb3 100644 --- a/frappe/event_streaming/doctype/document_type_field_mapping/document_type_field_mapping.py +++ b/frappe/event_streaming/doctype/document_type_field_mapping/document_type_field_mapping.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/document_type_mapping/document_type_mapping.py b/frappe/event_streaming/doctype/document_type_mapping/document_type_mapping.py index bcd2b275d1..04b5015296 100644 --- a/frappe/event_streaming/doctype/document_type_mapping/document_type_mapping.py +++ b/frappe/event_streaming/doctype/document_type_mapping/document_type_mapping.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE import json diff --git a/frappe/event_streaming/doctype/document_type_mapping/test_document_type_mapping.py b/frappe/event_streaming/doctype/document_type_mapping/test_document_type_mapping.py index 1d5c4862de..676d5040ff 100644 --- a/frappe/event_streaming/doctype/document_type_mapping/test_document_type_mapping.py +++ b/frappe/event_streaming/doctype/document_type_mapping/test_document_type_mapping.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/event_streaming/doctype/event_consumer/event_consumer.py b/frappe/event_streaming/doctype/event_consumer/event_consumer.py index bcd3d3be39..a2ae6f6651 100644 --- a/frappe/event_streaming/doctype/event_consumer/event_consumer.py +++ b/frappe/event_streaming/doctype/event_consumer/event_consumer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/event_consumer/test_event_consumer.py b/frappe/event_streaming/doctype/event_consumer/test_event_consumer.py index 605fc7982a..6f04af643e 100644 --- a/frappe/event_streaming/doctype/event_consumer/test_event_consumer.py +++ b/frappe/event_streaming/doctype/event_consumer/test_event_consumer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/event_streaming/doctype/event_consumer_document_type/event_consumer_document_type.py b/frappe/event_streaming/doctype/event_consumer_document_type/event_consumer_document_type.py index b33313087f..1ed15c5a75 100644 --- a/frappe/event_streaming/doctype/event_consumer_document_type/event_consumer_document_type.py +++ b/frappe/event_streaming/doctype/event_consumer_document_type/event_consumer_document_type.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/event_producer/event_producer.py b/frappe/event_streaming/doctype/event_producer/event_producer.py index adbb706c3d..f91c8a4fd4 100644 --- a/frappe/event_streaming/doctype/event_producer/event_producer.py +++ b/frappe/event_streaming/doctype/event_producer/event_producer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/event_producer/test_event_producer.py b/frappe/event_streaming/doctype/event_producer/test_event_producer.py index eafa7a0b51..168c9a61cf 100644 --- a/frappe/event_streaming/doctype/event_producer/test_event_producer.py +++ b/frappe/event_streaming/doctype/event_producer/test_event_producer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import json diff --git a/frappe/event_streaming/doctype/event_producer_document_type/event_producer_document_type.py b/frappe/event_streaming/doctype/event_producer_document_type/event_producer_document_type.py index 3e9623f56f..8f4c936792 100644 --- a/frappe/event_streaming/doctype/event_producer_document_type/event_producer_document_type.py +++ b/frappe/event_streaming/doctype/event_producer_document_type/event_producer_document_type.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/event_producer_last_update/event_producer_last_update.py b/frappe/event_streaming/doctype/event_producer_last_update/event_producer_last_update.py index 8e32e6fe6f..ec5cee7e78 100644 --- a/frappe/event_streaming/doctype/event_producer_last_update/event_producer_last_update.py +++ b/frappe/event_streaming/doctype/event_producer_last_update/event_producer_last_update.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/event_producer_last_update/test_event_producer_last_update.py b/frappe/event_streaming/doctype/event_producer_last_update/test_event_producer_last_update.py index 6054ec873f..ccdea6c694 100644 --- a/frappe/event_streaming/doctype/event_producer_last_update/test_event_producer_last_update.py +++ b/frappe/event_streaming/doctype/event_producer_last_update/test_event_producer_last_update.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/event_streaming/doctype/event_sync_log/event_sync_log.py b/frappe/event_streaming/doctype/event_sync_log/event_sync_log.py index c26ca46e05..a1d82ad08f 100644 --- a/frappe/event_streaming/doctype/event_sync_log/event_sync_log.py +++ b/frappe/event_streaming/doctype/event_sync_log/event_sync_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/event_sync_log/test_event_sync_log.py b/frappe/event_streaming/doctype/event_sync_log/test_event_sync_log.py index da90c8e634..13028cbac7 100644 --- a/frappe/event_streaming/doctype/event_sync_log/test_event_sync_log.py +++ b/frappe/event_streaming/doctype/event_sync_log/test_event_sync_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/event_streaming/doctype/event_update_log/event_update_log.py b/frappe/event_streaming/doctype/event_update_log/event_update_log.py index 658a3b47cc..e40f600484 100644 --- a/frappe/event_streaming/doctype/event_update_log/event_update_log.py +++ b/frappe/event_streaming/doctype/event_update_log/event_update_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # License: MIT. See LICENSE diff --git a/frappe/event_streaming/doctype/event_update_log/test_event_update_log.py b/frappe/event_streaming/doctype/event_update_log/test_event_update_log.py index 673164b8d7..0cbff47912 100644 --- a/frappe/event_streaming/doctype/event_update_log/test_event_update_log.py +++ b/frappe/event_streaming/doctype/event_update_log/test_event_update_log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/event_streaming/doctype/event_update_log_consumer/event_update_log_consumer.py b/frappe/event_streaming/doctype/event_update_log_consumer/event_update_log_consumer.py index 4f00504538..69da7db92e 100644 --- a/frappe/event_streaming/doctype/event_update_log_consumer/event_update_log_consumer.py +++ b/frappe/event_streaming/doctype/event_update_log_consumer/event_update_log_consumer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/exceptions.py b/frappe/exceptions.py index 755c21c240..c3bb45caea 100644 --- a/frappe/exceptions.py +++ b/frappe/exceptions.py @@ -76,7 +76,7 @@ class ImproperDBConfigurationError(Exception): def __init__(self, reason, msg=None): if not msg: msg = "MariaDb is not properly configured" - super(ImproperDBConfigurationError, self).__init__(msg) + super().__init__(msg) self.reason = reason diff --git a/frappe/frappeclient.py b/frappe/frappeclient.py index 04087463bc..474a5b06c4 100644 --- a/frappe/frappeclient.py +++ b/frappe/frappeclient.py @@ -26,7 +26,7 @@ class FrappeException(Exception): pass -class FrappeClient(object): +class FrappeClient: def __init__( self, url, @@ -85,11 +85,9 @@ class FrappeClient(object): def setup_key_authentication_headers(self): if self.api_key and self.api_secret: - token = base64.b64encode( - ("{}:{}".format(self.api_key, self.api_secret)).encode("utf-8") - ).decode("utf-8") + token = base64.b64encode((f"{self.api_key}:{self.api_secret}").encode()).decode("utf-8") auth_header = { - "Authorization": "Basic {}".format(token), + "Authorization": f"Basic {token}", } self.headers.update(auth_header) @@ -266,7 +264,7 @@ class FrappeClient(object): # build - attach children to parents if tables: docs = [frappe._dict(doc) for doc in docs] - docs_map = dict((doc.name, doc) for doc in docs) + docs_map = {doc.name: doc for doc in docs} for fieldname in tables: for child in tables[fieldname]: diff --git a/frappe/geo/country_info.py b/frappe/geo/country_info.py index 1de8467a6a..2aefa27170 100644 --- a/frappe/geo/country_info.py +++ b/frappe/geo/country_info.py @@ -22,7 +22,7 @@ def get_country_info(country=None): def get_all(): - with open(os.path.join(os.path.dirname(__file__), "country_info.json"), "r") as local_info: + with open(os.path.join(os.path.dirname(__file__), "country_info.json")) as local_info: all_data = json.loads(local_info.read()) return all_data @@ -59,7 +59,7 @@ def get_translated_dict(): def update(): - with open(os.path.join(os.path.dirname(__file__), "currency_info.json"), "r") as nformats: + with open(os.path.join(os.path.dirname(__file__), "currency_info.json")) as nformats: nformats = json.loads(nformats.read()) all_data = get_all() diff --git a/frappe/geo/doctype/country/__init__.py b/frappe/geo/doctype/country/__init__.py index 8b13789179..e69de29bb2 100644 --- a/frappe/geo/doctype/country/__init__.py +++ b/frappe/geo/doctype/country/__init__.py @@ -1 +0,0 @@ - diff --git a/frappe/geo/doctype/currency/__init__.py b/frappe/geo/doctype/currency/__init__.py index 8b13789179..e69de29bb2 100644 --- a/frappe/geo/doctype/currency/__init__.py +++ b/frappe/geo/doctype/currency/__init__.py @@ -1 +0,0 @@ - diff --git a/frappe/geo/doctype/currency/currency.json b/frappe/geo/doctype/currency/currency.json index db3fa5a19f..c51ab7f063 100644 --- a/frappe/geo/doctype/currency/currency.json +++ b/frappe/geo/doctype/currency/currency.json @@ -15,6 +15,7 @@ "fraction_units", "smallest_currency_fraction_value", "symbol", + "symbol_on_right", "number_format" ], "fields": [ @@ -69,16 +70,23 @@ "in_list_view": 1, "label": "Number Format", "options": "\n#,###.##\n#.###,##\n# ###.##\n# ###,##\n#'###.##\n#, ###.##\n#,##,###.##\n#,###.###\n#.###\n#,###" + }, + { + "default": "0", + "fieldname": "symbol_on_right", + "fieldtype": "Check", + "label": "Show Currency Symbol on Right Side" } ], "icon": "fa fa-bitcoin", "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2020-10-29 06:33:12.879978", + "modified": "2022-07-04 09:42:52.425440", "modified_by": "Administrator", "module": "Geo", "name": "Currency", + "naming_rule": "By fieldname", "owner": "Administrator", "permissions": [ { @@ -109,5 +117,6 @@ ], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index d4b225b055..53caed452d 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -62,7 +62,7 @@ def return_location(doctype, filters_sql): if filters_sql: try: coords = frappe.db.sql( - """SELECT name, location FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True + f"""SELECT name, location FROM `tab{doctype}` WHERE {filters_sql}""", as_dict=True ) except frappe.db.InternalError: frappe.msgprint(frappe._("This Doctype does not contain location fields"), raise_exception=True) @@ -77,7 +77,7 @@ def return_coordinates(doctype, filters_sql): if filters_sql: try: coords = frappe.db.sql( - """SELECT name, latitude, longitude FROM `tab{}` WHERE {}""".format(doctype, filters_sql), + f"""SELECT name, latitude, longitude FROM `tab{doctype}` WHERE {filters_sql}""", as_dict=True, ) except frappe.db.InternalError: diff --git a/frappe/hooks.py b/frappe/hooks.py index a5f532ad4d..54d068fa9d 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -222,7 +222,6 @@ scheduler_events = { "frappe.desk.doctype.event.event.send_event_digest", "frappe.sessions.clear_expired_sessions", "frappe.email.doctype.notification.notification.trigger_daily_alerts", - "frappe.utils.scheduler.restrict_scheduler_events_if_dormant", "frappe.website.doctype.personal_data_deletion_request.personal_data_deletion_request.remove_unverified_record", "frappe.desk.form.document_follow.send_daily_updates", "frappe.social.doctype.energy_point_settings.energy_point_settings.allocate_review_points", diff --git a/frappe/installer.py b/frappe/installer.py index 786b5174ba..32ab45e383 100644 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -5,7 +5,6 @@ import json import os import sys from collections import OrderedDict -from typing import Dict, List, Tuple import click @@ -49,7 +48,7 @@ def _new_site( from frappe.utils import get_site_path, scheduler, touch_file if not force and os.path.exists(site): - print("Site {0} already exists".format(site)) + print(f"Site {site} already exists") sys.exit(1) if no_mariadb_socket and not db_type == "mariadb": @@ -162,7 +161,7 @@ def install_db( frappe.flags.in_install_db = False -def find_org(org_repo: str) -> Tuple[str, str]: +def find_org(org_repo: str) -> tuple[str, str]: """find the org a repo is in find_org() @@ -190,7 +189,7 @@ def find_org(org_repo: str) -> Tuple[str, str]: raise InvalidRemoteException -def fetch_details_from_tag(_tag: str) -> Tuple[str, str, str]: +def fetch_details_from_tag(_tag: str) -> tuple[str, str, str]: """parse org, repo, tag from string fetch_details_from_tag() @@ -274,7 +273,7 @@ def install_app(name, verbose=False, set_as_patched=True, force=False): click.secho(f"App {name} already installed", fg="yellow") return - print("\nInstalling {0}...".format(name)) + print(f"\nInstalling {name}...") if name != "frappe": frappe.only_for("System Manager") @@ -382,7 +381,7 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) frappe.flags.in_uninstall = False -def _delete_modules(modules: List[str], dry_run: bool) -> List[str]: +def _delete_modules(modules: list[str], dry_run: bool) -> list[str]: """Delete modules belonging to the app and all related doctypes. Note: All record linked linked to Module Def are also deleted. @@ -415,7 +414,7 @@ def _delete_modules(modules: List[str], dry_run: bool) -> List[str]: def _delete_linked_documents( - module_name: str, doctype_linkfield_map: Dict[str, str], dry_run: bool + module_name: str, doctype_linkfield_map: dict[str, str], dry_run: bool ) -> None: """Deleted all records linked with module def""" @@ -426,7 +425,7 @@ def _delete_linked_documents( frappe.delete_doc(doctype, record, ignore_on_trash=True, force=True) -def _get_module_linked_doctype_field_map() -> Dict[str, str]: +def _get_module_linked_doctype_field_map() -> dict[str, str]: """Get all the doctypes which have module linked with them. returns ordered dictionary with doctype->link field mapping.""" @@ -455,7 +454,7 @@ def _get_module_linked_doctype_field_map() -> Dict[str, str]: return doctype_to_field_map -def _delete_doctypes(doctypes: List[str], dry_run: bool) -> None: +def _delete_doctypes(doctypes: list[str], dry_run: bool) -> None: for doctype in set(doctypes): print(f"* dropping Table for '{doctype}'...") if not dry_run: @@ -540,7 +539,7 @@ def update_site_config(key, value, validate=True, site_config_path=None): if not site_config_path: site_config_path = get_site_config_path() - with open(site_config_path, "r") as f: + with open(site_config_path) as f: site_config = json.loads(f.read()) # In case of non-int value @@ -675,7 +674,7 @@ def extract_sql_gzip(sql_gz_path): try: original_file = sql_gz_path decompressed_file = original_file.rstrip(".gz") - cmd = "gzip --decompress --force < {0} > {1}".format(original_file, decompressed_file) + cmd = f"gzip --decompress --force < {original_file} > {decompressed_file}" subprocess.check_call(cmd, shell=True) except Exception: raise @@ -811,7 +810,7 @@ def validate_database_sql(path, _raise=True): # dont bother checking if empty file if not empty_file: - with open(path, "r") as f: + with open(path) as f: for line in f: if "tabDefaultValue" in line: missing_table = False diff --git a/frappe/integrations/doctype/braintree_settings/braintree_settings.py b/frappe/integrations/doctype/braintree_settings/braintree_settings.py index 17330d7c84..35481c67c1 100644 --- a/frappe/integrations/doctype/braintree_settings/braintree_settings.py +++ b/frappe/integrations/doctype/braintree_settings/braintree_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -184,7 +183,7 @@ class BraintreeSettings(Document): ) def get_payment_url(self, **kwargs): - return get_url("./integrations/braintree_checkout?{0}".format(urlencode(kwargs))) + return get_url(f"./integrations/braintree_checkout?{urlencode(kwargs)}") def create_payment_request(self, data): self.data = frappe._dict(data) diff --git a/frappe/integrations/doctype/braintree_settings/test_braintree_settings.py b/frappe/integrations/doctype/braintree_settings/test_braintree_settings.py index 475a62be79..38d8909dfd 100644 --- a/frappe/integrations/doctype/braintree_settings/test_braintree_settings.py +++ b/frappe/integrations/doctype/braintree_settings/test_braintree_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/connected_app/connected_app.py b/frappe/integrations/doctype/connected_app/connected_app.py index e472193da8..308d1ca84a 100644 --- a/frappe/integrations/doctype/connected_app/connected_app.py +++ b/frappe/integrations/doctype/connected_app/connected_app.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/connected_app/test_connected_app.py b/frappe/integrations/doctype/connected_app/test_connected_app.py index 1597ec75bf..1acedff160 100644 --- a/frappe/integrations/doctype/connected_app/test_connected_app.py +++ b/frappe/integrations/doctype/connected_app/test_connected_app.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py index 8a6a7a4bfb..50c5fa8fe6 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -89,7 +88,7 @@ def take_backup_to_dropbox(retry_count=0, upload_db_backup=True): "frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backup_to_dropbox", queue="long", timeout=1500, - **args + **args, ) except Exception: if isinstance(error_log, str): @@ -212,7 +211,7 @@ def upload_file_to_dropbox(filename, folder, dropbox_client): mode = dropbox.files.WriteMode.overwrite f = open(encode(filename), "rb") - path = "{0}/{1}".format(folder, os.path.basename(filename)) + path = f"{folder}/{os.path.basename(filename)}" try: if file_size <= chunk_size: @@ -234,7 +233,7 @@ def upload_file_to_dropbox(filename, folder, dropbox_client): cursor.offset = f.tell() except dropbox.exceptions.ApiError as e: if isinstance(e.error, dropbox.files.UploadError): - error = "File Path: {path}\n".format(path=path) + error = f"File Path: {path}\n" error += frappe.get_traceback() frappe.log_error(error) else: @@ -326,7 +325,7 @@ def delete_older_backups(dropbox_client, folder_path, to_keep): def get_redirect_url(): if not frappe.conf.dropbox_broker_site: frappe.conf.dropbox_broker_site = "https://dropbox.erpnext.com" - url = "{0}/api/method/dropbox_erpnext_broker.www.setup_dropbox.get_authotize_url".format( + url = "{}/api/method/dropbox_erpnext_broker.www.setup_dropbox.get_authotize_url".format( frappe.conf.dropbox_broker_site ) diff --git a/frappe/integrations/doctype/dropbox_settings/test_dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/test_dropbox_settings.py index e73cf03268..b165e03780 100644 --- a/frappe/integrations/doctype/dropbox_settings/test_dropbox_settings.py +++ b/frappe/integrations/doctype/dropbox_settings/test_dropbox_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/integrations/doctype/google_calendar/google_calendar.py b/frappe/integrations/doctype/google_calendar/google_calendar.py index 71f0e83f80..d8dc7fab1d 100644 --- a/frappe/integrations/doctype/google_calendar/google_calendar.py +++ b/frappe/integrations/doctype/google_calendar/google_calendar.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -140,7 +139,7 @@ def authorize_access(g_calendar, reauthorize=None): frappe.db.commit() frappe.local.response["type"] = "redirect" - frappe.local.response["location"] = "/app/Form/{0}/{1}".format( + frappe.local.response["location"] = "/app/Form/{}/{}".format( quote("Google Calendar"), quote(google_calendar.name) ) diff --git a/frappe/integrations/doctype/google_contacts/google_contacts.py b/frappe/integrations/doctype/google_contacts/google_contacts.py index c26366f71a..5e4869be43 100644 --- a/frappe/integrations/doctype/google_contacts/google_contacts.py +++ b/frappe/integrations/doctype/google_contacts/google_contacts.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -91,7 +90,7 @@ def authorize_access(g_contact, reauthorize=None): frappe.db.commit() frappe.local.response["type"] = "redirect" - frappe.local.response["location"] = "/app/Form/Google%20Contacts/{}".format(google_contact.name) + frappe.local.response["location"] = f"/app/Form/Google%20Contacts/{google_contact.name}" frappe.msgprint(_("Google Contacts has been configured.")) except Exception as e: diff --git a/frappe/integrations/doctype/google_drive/google_drive.py b/frappe/integrations/doctype/google_drive/google_drive.py index 347488ee44..c472cbc741 100644 --- a/frappe/integrations/doctype/google_drive/google_drive.py +++ b/frappe/integrations/doctype/google_drive/google_drive.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -101,7 +100,7 @@ def authorize_access(reauthorize=None): frappe.db.commit() frappe.local.response["type"] = "redirect" - frappe.local.response["location"] = "/app/Form/{0}".format(quote("Google Drive")) + frappe.local.response["location"] = "/app/Form/{}".format(quote("Google Drive")) frappe.msgprint(_("Google Drive has been configured.")) except Exception as e: @@ -243,7 +242,7 @@ def upload_system_backup_to_google_drive(): media = MediaFileUpload( get_absolute_path(filename=fileurl), mimetype="application/gzip", resumable=True ) - except IOError as e: + except OSError as e: frappe.throw(_("Google Drive - Could not locate - {0}").format(e)) try: @@ -272,7 +271,7 @@ def weekly_backup(): def get_absolute_path(filename): file_path = os.path.join(get_backups_path()[2:], os.path.basename(filename)) - return "{0}/sites/{1}".format(get_bench_path(), file_path) + return f"{get_bench_path()}/sites/{file_path}" def set_progress(progress, message): diff --git a/frappe/integrations/doctype/google_drive/test_google_drive.py b/frappe/integrations/doctype/google_drive/test_google_drive.py index 17f5b152ca..4dcc79afd6 100644 --- a/frappe/integrations/doctype/google_drive/test_google_drive.py +++ b/frappe/integrations/doctype/google_drive/test_google_drive.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/integrations/doctype/google_settings/google_settings.py b/frappe/integrations/doctype/google_settings/google_settings.py index 0d5f9cb00d..c70a4b531f 100644 --- a/frappe/integrations/doctype/google_settings/google_settings.py +++ b/frappe/integrations/doctype/google_settings/google_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/google_settings/test_google_settings.py b/frappe/integrations/doctype/google_settings/test_google_settings.py index 53d59b1be0..8d07ffa54f 100644 --- a/frappe/integrations/doctype/google_settings/test_google_settings.py +++ b/frappe/integrations/doctype/google_settings/test_google_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies and Contributors # License: MIT. See LICENSE -from __future__ import unicode_literals import unittest diff --git a/frappe/integrations/doctype/integration_request/integration_request.py b/frappe/integrations/doctype/integration_request/integration_request.py index 4c99613161..334736bc9b 100644 --- a/frappe/integrations/doctype/integration_request/integration_request.py +++ b/frappe/integrations/doctype/integration_request/integration_request.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/integration_request/test_integration_request.py b/frappe/integrations/doctype/integration_request/test_integration_request.py index d14af481e8..45963d5096 100644 --- a/frappe/integrations/doctype/integration_request/test_integration_request.py +++ b/frappe/integrations/doctype/integration_request/test_integration_request.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/ldap_group_mapping/ldap_group_mapping.py b/frappe/integrations/doctype/ldap_group_mapping/ldap_group_mapping.py index f1b242e4bb..853cfc96a1 100644 --- a/frappe/integrations/doctype/ldap_group_mapping/ldap_group_mapping.py +++ b/frappe/integrations/doctype/ldap_group_mapping/ldap_group_mapping.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/ldap_settings/ldap_settings.py b/frappe/integrations/doctype/ldap_settings/ldap_settings.py index 96007ee918..ef6493717f 100644 --- a/frappe/integrations/doctype/ldap_settings/ldap_settings.py +++ b/frappe/integrations/doctype/ldap_settings/ldap_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -137,7 +136,7 @@ class LDAPSettings(Document): def sync_roles(self, user, additional_groups=None): - current_roles = set(d.role for d in user.get("roles")) + current_roles = {d.role for d in user.get("roles")} needed_roles = set() needed_roles.add(self.default_role) @@ -209,14 +208,12 @@ class LDAPSettings(Document): if type(user) is not ldap3.abstract.entry.Entry: raise TypeError( - "Invalid type, attribute {0} must be of type '{1}'".format( - "user", "ldap3.abstract.entry.Entry" - ) + "Invalid type, attribute {} must be of type '{}'".format("user", "ldap3.abstract.entry.Entry") ) if type(conn) is not ldap3.core.connection.Connection: raise TypeError( - "Invalid type, attribute {0} must be of type '{1}'".format("conn", "ldap3.Connection") + "Invalid type, attribute {} must be of type '{}'".format("conn", "ldap3.Connection") ) fetch_ldap_groups = None @@ -254,7 +251,7 @@ class LDAPSettings(Document): if ldap_object_class is not None: conn.search( search_base=self.ldap_search_path_group, - search_filter="(&(objectClass={0})({1}={2}))".format( + search_filter="(&(objectClass={})({}={}))".format( ldap_object_class, ldap_group_members_attribute, user_search_str ), attributes=["cn"], @@ -283,7 +280,7 @@ class LDAPSettings(Document): conn.search( search_base=self.ldap_search_path_user, - search_filter="{0}".format(user_filter), + search_filter=f"{user_filter}", attributes=ldap_attributes, ) @@ -309,7 +306,7 @@ class LDAPSettings(Document): from ldap3 import HASHED_SALTED_SHA, MODIFY_REPLACE from ldap3.utils.hashed import hashed - search_filter = "({0}={1})".format(self.ldap_email_field, user) + search_filter = f"({self.ldap_email_field}={user})" conn = self.connect_to_ldap( self.base_dn, self.get_password(raise_exception=False), read_only=False diff --git a/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py b/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py index 0651932843..f53b5291b3 100644 --- a/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py +++ b/frappe/integrations/doctype/ldap_settings/test_ldap_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and Contributors # License: MIT. See LICENSE import functools @@ -204,7 +203,7 @@ class LDAP_TestCase: frappe.get_doc(localdoc).save() - self.fail("Document LDAP Settings field [{0}] is not mandatory".format(mandatory_field)) + self.fail(f"Document LDAP Settings field [{mandatory_field}] is not mandatory") except frappe.exceptions.MandatoryError: pass @@ -227,9 +226,7 @@ class LDAP_TestCase: frappe.get_doc(localdoc).save() except frappe.exceptions.MandatoryError: - self.fail( - "Document LDAP Settings field [{0}] should not be mandatory".format(non_mandatory_field) - ) + self.fail(f"Document LDAP Settings field [{non_mandatory_field}] should not be mandatory") @mock_ldap_connection def test_validation_ldap_search_string(self): @@ -252,7 +249,7 @@ class LDAP_TestCase: try: frappe.get_doc(localdoc).save() - self.fail("LDAP search string [{0}] should not validate".format(invalid_search_string)) + self.fail(f"LDAP search string [{invalid_search_string}] should not validate") except frappe.exceptions.ValidationError: pass @@ -298,7 +295,7 @@ class LDAP_TestCase: ): self.fail( - "ldap3.Connection was called with {0}, failed reason: [{1}]".format( + "ldap3.Connection was called with {}, failed reason: [{}]".format( kwargs[connection_arg], prevent_connection_parameters[connection_arg][kwargs[connection_arg]], ) @@ -475,7 +472,7 @@ class LDAP_TestCase: self.assertTrue( len(updated_user_roles) == len(test_user_data[test_user]), - "syncing of the user roles failed. {0} != {1} for user {2}".format( + "syncing of the user roles failed. {} != {} for user {}".format( len(updated_user_roles), len(test_user_data[test_user]), test_user ), ) @@ -484,7 +481,7 @@ class LDAP_TestCase: self.assertTrue( role_to_group_map[user_role] in test_user_data[test_user], - "during sync_roles(), the user was given role {0} which should not have occured".format( + "during sync_roles(), the user was given role {} which should not have occured".format( user_role ), ) @@ -609,7 +606,7 @@ class LDAP_TestCase: self.assertTrue( str(display_massage.exception).lower() == "invalid username or password", - "invalid credentials passed authentication [user: {0}, password: {1}]".format( + "invalid credentials passed authentication [user: {}, password: {}]".format( username, password ), ) diff --git a/frappe/integrations/doctype/oauth_authorization_code/oauth_authorization_code.py b/frappe/integrations/doctype/oauth_authorization_code/oauth_authorization_code.py index 4ef6f65dc7..431d27bc04 100644 --- a/frappe/integrations/doctype/oauth_authorization_code/oauth_authorization_code.py +++ b/frappe/integrations/doctype/oauth_authorization_code/oauth_authorization_code.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/oauth_authorization_code/test_oauth_authorization_code.py b/frappe/integrations/doctype/oauth_authorization_code/test_oauth_authorization_code.py index 72cb789ebb..2036a42f15 100644 --- a/frappe/integrations/doctype/oauth_authorization_code/test_oauth_authorization_code.py +++ b/frappe/integrations/doctype/oauth_authorization_code/test_oauth_authorization_code.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/oauth_bearer_token/oauth_bearer_token.py b/frappe/integrations/doctype/oauth_bearer_token/oauth_bearer_token.py index 515d3d2ba3..2a17035571 100644 --- a/frappe/integrations/doctype/oauth_bearer_token/oauth_bearer_token.py +++ b/frappe/integrations/doctype/oauth_bearer_token/oauth_bearer_token.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/oauth_bearer_token/test_oauth_bearer_token.py b/frappe/integrations/doctype/oauth_bearer_token/test_oauth_bearer_token.py index 9dea8f482a..3439096809 100644 --- a/frappe/integrations/doctype/oauth_bearer_token/test_oauth_bearer_token.py +++ b/frappe/integrations/doctype/oauth_bearer_token/test_oauth_bearer_token.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/oauth_client/oauth_client.py b/frappe/integrations/doctype/oauth_client/oauth_client.py index 09f6e3aced..ab40467751 100644 --- a/frappe/integrations/doctype/oauth_client/oauth_client.py +++ b/frappe/integrations/doctype/oauth_client/oauth_client.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/oauth_client/test_oauth_client.py b/frappe/integrations/doctype/oauth_client/test_oauth_client.py index dd1b25239a..8fd732673e 100644 --- a/frappe/integrations/doctype/oauth_client/test_oauth_client.py +++ b/frappe/integrations/doctype/oauth_client/test_oauth_client.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py b/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py index 2aefd591a1..984382df9d 100644 --- a/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py +++ b/frappe/integrations/doctype/oauth_provider_settings/oauth_provider_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/oauth_scope/oauth_scope.py b/frappe/integrations/doctype/oauth_scope/oauth_scope.py index a30d087cc0..1db49a3818 100644 --- a/frappe/integrations/doctype/oauth_scope/oauth_scope.py +++ b/frappe/integrations/doctype/oauth_scope/oauth_scope.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/paypal_settings/paypal_settings.py b/frappe/integrations/doctype/paypal_settings/paypal_settings.py index 3568b77baf..99c499200b 100644 --- a/frappe/integrations/doctype/paypal_settings/paypal_settings.py +++ b/frappe/integrations/doctype/paypal_settings/paypal_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -193,7 +192,7 @@ class PayPalSettings(Document): params.update( { "METHOD": "SetExpressCheckout", - "returnUrl": get_url("{0}.get_express_checkout_details".format(api_path)), + "returnUrl": get_url(f"{api_path}.get_express_checkout_details"), "cancelUrl": get_url("/payment-cancel"), "PAYMENTREQUEST_0_PAYMENTACTION": "SALE", "PAYMENTREQUEST_0_AMT": kwargs["amount"], @@ -331,7 +330,7 @@ def confirm_payment(token): ).run_method("on_payment_authorized", "Completed") frappe.db.commit() - redirect_url = "/integrations/payment-success?doctype={0}&docname={1}".format( + redirect_url = "/integrations/payment-success?doctype={}&docname={}".format( data.get("reference_doctype"), data.get("reference_docname") ) else: @@ -404,7 +403,7 @@ def create_recurring_profile(token, payerid): ).run_method("on_payment_authorized", status_changed_to) frappe.db.commit() - redirect_url = "/integrations/payment-success?doctype={0}&docname={1}".format( + redirect_url = "/integrations/payment-success?doctype={}&docname={}".format( data.get("reference_doctype"), data.get("reference_docname") ) else: @@ -427,11 +426,9 @@ def get_redirect_uri(doc, token, payerid): data = json.loads(doc.data) if data.get("subscription_details") or data.get("subscription_id"): - return get_url( - "{0}.create_recurring_profile?token={1}&payerid={2}".format(api_path, token, payerid) - ) + return get_url(f"{api_path}.create_recurring_profile?token={token}&payerid={payerid}") else: - return get_url("{0}.confirm_payment?token={1}".format(api_path, token)) + return get_url(f"{api_path}.confirm_payment?token={token}") def manage_recurring_payment_profile_status(profile_id, action, args, url): @@ -474,7 +471,7 @@ def ipn_handler(): queue="long", timeout=600, is_async=True, - **{"doctype": "Integration Request", "docname": doc.name} + **{"doctype": "Integration Request", "docname": doc.name}, ) except frappe.InvalidStatusError: diff --git a/frappe/integrations/doctype/paytm_settings/paytm_settings.py b/frappe/integrations/doctype/paytm_settings/paytm_settings.py index d8c9159303..81a5f45f47 100644 --- a/frappe/integrations/doctype/paytm_settings/paytm_settings.py +++ b/frappe/integrations/doctype/paytm_settings/paytm_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -37,7 +36,7 @@ class PaytmSettings(Document): integration_request = create_request_log(kwargs, service_name="Paytm") kwargs.update(dict(order_id=integration_request.name)) - return get_url("./integrations/paytm_checkout?{0}".format(urlencode(kwargs))) + return get_url(f"./integrations/paytm_checkout?{urlencode(kwargs)}") def get_paytm_config(): diff --git a/frappe/integrations/doctype/paytm_settings/test_paytm_settings.py b/frappe/integrations/doctype/paytm_settings/test_paytm_settings.py index d9e72e344c..91b69d5aec 100644 --- a/frappe/integrations/doctype/paytm_settings/test_paytm_settings.py +++ b/frappe/integrations/doctype/paytm_settings/test_paytm_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # License: MIT. See LICENSE # import frappe diff --git a/frappe/integrations/doctype/query_parameters/query_parameters.py b/frappe/integrations/doctype/query_parameters/query_parameters.py index 09f039a764..b501c0c3e8 100644 --- a/frappe/integrations/doctype/query_parameters/query_parameters.py +++ b/frappe/integrations/doctype/query_parameters/query_parameters.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index b13319803f..a79e626b49 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -124,9 +123,7 @@ class RazorpaySettings(Document): "quantity": 1 (The total amount is calculated as item.amount * quantity) } """ - url = "https://api.razorpay.com/v1/subscriptions/{0}/addons".format( - kwargs.get("subscription_id") - ) + url = "https://api.razorpay.com/v1/subscriptions/{}/addons".format(kwargs.get("subscription_id")) try: if not frappe.conf.converted_rupee_to_paisa: @@ -195,7 +192,7 @@ class RazorpaySettings(Document): def get_payment_url(self, **kwargs): integration_request = create_request_log(kwargs, service_name="Razorpay") - return get_url("./integrations/razorpay_checkout?token={0}".format(integration_request.name)) + return get_url(f"./integrations/razorpay_checkout?token={integration_request.name}") def create_order(self, **kwargs): # Creating Orders https://razorpay.com/docs/api/orders/ @@ -257,7 +254,7 @@ class RazorpaySettings(Document): try: resp = make_get_request( - "https://api.razorpay.com/v1/payments/{0}".format(self.data.razorpay_payment_id), + f"https://api.razorpay.com/v1/payments/{self.data.razorpay_payment_id}", auth=(settings.api_key, settings.api_secret), ) @@ -303,7 +300,7 @@ class RazorpaySettings(Document): if custom_redirect_to: redirect_to = custom_redirect_to - redirect_url = "payment-success?doctype={0}&docname={1}".format( + redirect_url = "payment-success?doctype={}&docname={}".format( self.data.reference_doctype, self.data.reference_docname ) else: @@ -339,7 +336,7 @@ class RazorpaySettings(Document): try: resp = make_post_request( - "https://api.razorpay.com/v1/subscriptions/{0}/cancel".format(subscription_id), + f"https://api.razorpay.com/v1/subscriptions/{subscription_id}/cancel", auth=(settings.api_key, settings.api_secret), ) except Exception: @@ -383,14 +380,14 @@ def capture_payment(is_sandbox=False, sanbox_response=None): settings = controller.get_settings(data) resp = make_get_request( - "https://api.razorpay.com/v1/payments/{0}".format(data.get("razorpay_payment_id")), + "https://api.razorpay.com/v1/payments/{}".format(data.get("razorpay_payment_id")), auth=(settings.api_key, settings.api_secret), data={"amount": data.get("amount")}, ) if resp.get("status") == "authorized": resp = make_post_request( - "https://api.razorpay.com/v1/payments/{0}/capture".format(data.get("razorpay_payment_id")), + "https://api.razorpay.com/v1/payments/{}/capture".format(data.get("razorpay_payment_id")), auth=(settings.api_key, settings.api_secret), data={"amount": data.get("amount")}, ) @@ -403,7 +400,7 @@ def capture_payment(is_sandbox=False, sanbox_response=None): doc.status = "Failed" doc.error = frappe.get_traceback() doc.save() - frappe.log_error(doc.error, "{0} Failed".format(doc.name)) + frappe.log_error(doc.error, f"{doc.name} Failed") @frappe.whitelist(allow_guest=True) @@ -498,7 +495,7 @@ def razorpay_subscription_callback(): queue="long", timeout=600, is_async=True, - **{"doctype": "Integration Request", "docname": doc.name} + **{"doctype": "Integration Request", "docname": doc.name}, ) except frappe.InvalidStatusError: @@ -521,7 +518,7 @@ def validate_payment_callback(data): settings = controller.get_settings(data) resp = make_get_request( - "https://api.razorpay.com/v1/subscriptions/{0}".format(subscription_id), + f"https://api.razorpay.com/v1/subscriptions/{subscription_id}", auth=(settings.api_key, settings.api_secret), ) diff --git a/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py b/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py index 015d4f0467..1c2d39be10 100755 --- a/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py +++ b/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE import os diff --git a/frappe/integrations/doctype/s3_backup_settings/test_s3_backup_settings.py b/frappe/integrations/doctype/s3_backup_settings/test_s3_backup_settings.py index c6dbee2c20..48b1ccd113 100755 --- a/frappe/integrations/doctype/s3_backup_settings/test_s3_backup_settings.py +++ b/frappe/integrations/doctype/s3_backup_settings/test_s3_backup_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/slack_webhook_url/slack_webhook_url.py b/frappe/integrations/doctype/slack_webhook_url/slack_webhook_url.py index cf6a23fb34..d71d7075a6 100644 --- a/frappe/integrations/doctype/slack_webhook_url/slack_webhook_url.py +++ b/frappe/integrations/doctype/slack_webhook_url/slack_webhook_url.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/slack_webhook_url/test_slack_webhook_url.py b/frappe/integrations/doctype/slack_webhook_url/test_slack_webhook_url.py index 4bd71033bb..16b1bcd3c2 100644 --- a/frappe/integrations/doctype/slack_webhook_url/test_slack_webhook_url.py +++ b/frappe/integrations/doctype/slack_webhook_url/test_slack_webhook_url.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/social_login_key/social_login_key.py b/frappe/integrations/doctype/social_login_key/social_login_key.py index 8c19767107..e38f19bb2b 100644 --- a/frappe/integrations/doctype/social_login_key/social_login_key.py +++ b/frappe/integrations/doctype/social_login_key/social_login_key.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -69,7 +68,7 @@ class SocialLoginKey(Document): if self.provider_name in icon_map: icon_file = icon_map[self.provider_name] - self.icon = "/assets/frappe/icons/social/{0}".format(icon_file) + self.icon = f"/assets/frappe/icons/social/{icon_file}" @frappe.whitelist() def get_social_login_provider(self, provider, initialize=False): diff --git a/frappe/integrations/doctype/social_login_key/test_social_login_key.py b/frappe/integrations/doctype/social_login_key/test_social_login_key.py index be4c1f7c49..c51ccb2c0f 100644 --- a/frappe/integrations/doctype/social_login_key/test_social_login_key.py +++ b/frappe/integrations/doctype/social_login_key/test_social_login_key.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/stripe_settings/stripe_settings.py b/frappe/integrations/doctype/stripe_settings/stripe_settings.py index bc8b0dfa17..8e1d383790 100644 --- a/frappe/integrations/doctype/stripe_settings/stripe_settings.py +++ b/frappe/integrations/doctype/stripe_settings/stripe_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -163,7 +162,7 @@ class StripeSettings(Document): def validate_stripe_credentails(self): if self.publishable_key and self.secret_key: header = { - "Authorization": "Bearer {0}".format( + "Authorization": "Bearer {}".format( self.get_password(fieldname="secret_key", raise_exception=False) ) } @@ -190,7 +189,7 @@ class StripeSettings(Document): ) def get_payment_url(self, **kwargs): - return get_url("./integrations/stripe_checkout?{0}".format(urlencode(kwargs))) + return get_url(f"./integrations/stripe_checkout?{urlencode(kwargs)}") def create_request(self, data): import stripe diff --git a/frappe/integrations/doctype/stripe_settings/test_stripe_settings.py b/frappe/integrations/doctype/stripe_settings/test_stripe_settings.py index e13359fa6d..eed87bfcaf 100644 --- a/frappe/integrations/doctype/stripe_settings/test_stripe_settings.py +++ b/frappe/integrations/doctype/stripe_settings/test_stripe_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/token_cache/test_token_cache.py b/frappe/integrations/doctype/token_cache/test_token_cache.py index 6a3b16e72c..a9366d84d3 100644 --- a/frappe/integrations/doctype/token_cache/test_token_cache.py +++ b/frappe/integrations/doctype/token_cache/test_token_cache.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/token_cache/token_cache.py b/frappe/integrations/doctype/token_cache/token_cache.py index 7d961fe1cc..25f07a16ba 100644 --- a/frappe/integrations/doctype/token_cache/token_cache.py +++ b/frappe/integrations/doctype/token_cache/token_cache.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/webhook/__init__.py b/frappe/integrations/doctype/webhook/__init__.py index 915d2819ee..8e9c72c1a9 100644 --- a/frappe/integrations/doctype/webhook/__init__.py +++ b/frappe/integrations/doctype/webhook/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/webhook/test_webhook.py b/frappe/integrations/doctype/webhook/test_webhook.py index 5386a75573..5ac75f5b52 100644 --- a/frappe/integrations/doctype/webhook/test_webhook.py +++ b/frappe/integrations/doctype/webhook/test_webhook.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 22abcf9a99..27fdd662ed 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -8,7 +7,6 @@ import hashlib import hmac import json from time import sleep -from typing import Dict, Optional from urllib.parse import urlparse import requests @@ -114,7 +112,7 @@ def enqueue_webhook(doc, webhook) -> None: webhook.log_error("Webhook failed") -def log_request(url: str, headers: Dict, data: Dict, res: Optional[requests.Response] = None): +def log_request(url: str, headers: dict, data: dict, res: requests.Response | None = None): request_log = frappe.get_doc( { "doctype": "Webhook Request Log", diff --git a/frappe/integrations/doctype/webhook_data/webhook_data.py b/frappe/integrations/doctype/webhook_data/webhook_data.py index 1bb0d901df..39016cb864 100644 --- a/frappe/integrations/doctype/webhook_data/webhook_data.py +++ b/frappe/integrations/doctype/webhook_data/webhook_data.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/doctype/webhook_header/webhook_header.py b/frappe/integrations/doctype/webhook_header/webhook_header.py index 9478d227e4..f5f85d1afe 100644 --- a/frappe/integrations/doctype/webhook_header/webhook_header.py +++ b/frappe/integrations/doctype/webhook_header/webhook_header.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/integrations/frappe_providers/__init__.py b/frappe/integrations/frappe_providers/__init__.py index 161937a936..630c2c08b4 100644 --- a/frappe/integrations/frappe_providers/__init__.py +++ b/frappe/integrations/frappe_providers/__init__.py @@ -9,5 +9,5 @@ def migrate_to(local_site, frappe_provider): if frappe_provider in ("frappe.cloud", "frappecloud.com"): return frappecloud_migrator(local_site) else: - print("{} is not supported yet".format(frappe_provider)) + print(f"{frappe_provider} is not supported yet") sys.exit(1) diff --git a/frappe/integrations/frappe_providers/frappecloud.py b/frappe/integrations/frappe_providers/frappecloud.py index 0a01989d5e..64aa847a0e 100644 --- a/frappe/integrations/frappe_providers/frappecloud.py +++ b/frappe/integrations/frappe_providers/frappecloud.py @@ -8,7 +8,7 @@ import frappe def frappecloud_migrator(local_site): print("Retrieving Site Migrator...") remote_site = frappe.conf.frappecloud_url or "frappecloud.com" - request_url = "https://{}/api/method/press.api.script".format(remote_site) + request_url = f"https://{remote_site}/api/method/press.api.script" request = requests.get(request_url) if request.status_code / 100 != 2: @@ -32,5 +32,5 @@ def frappecloud_migrator(local_site): py = sys.executable script = tempfile.NamedTemporaryFile(mode="w") script.write(script_contents) - print("Site Migrator stored at {}".format(script.name)) + print(f"Site Migrator stored at {script.name}") os.execv(py, [py, script.name, local_site]) diff --git a/frappe/integrations/offsite_backup_utils.py b/frappe/integrations/offsite_backup_utils.py index 307f1525fe..620f692ad0 100644 --- a/frappe/integrations/offsite_backup_utils.py +++ b/frappe/integrations/offsite_backup_utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -13,8 +12,8 @@ def send_email(success, service_name, doctype, email_field, error_status=None): recipients = get_recipients(doctype, email_field) if not recipients: frappe.log_error( - "No Email Recipient found for {0}".format(service_name), - "{0}: Failed to send backup status email".format(service_name), + f"No Email Recipient found for {service_name}", + f"{service_name}: Failed to send backup status email", ) return @@ -25,15 +24,15 @@ def send_email(success, service_name, doctype, email_field, error_status=None): subject = "Backup Upload Successful" message = """

Backup Uploaded Successfully!

-

Hi there, this is just to inform you that your backup was successfully uploaded to your {0} bucket. So relax!

""".format( +

Hi there, this is just to inform you that your backup was successfully uploaded to your {} bucket. So relax!

""".format( service_name ) else: subject = "[Warning] Backup Upload Failed" message = """

Backup Upload Failed!

-

Oops, your automated backup to {0} failed.

-

Error message: {1}

+

Oops, your automated backup to {} failed.

+

Error message: {}

Please contact your system manager for more information.

""".format( service_name, error_status ) diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index 1440c80399..f215a73dc6 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # License: MIT. See LICENSE @@ -50,7 +49,7 @@ def create_request_log( error=None, request_headers=None, output=None, - **kwargs + **kwargs, ): """ DEPRECATED: The parameter integration_type will be removed in the next major release. @@ -102,7 +101,7 @@ def get_payment_gateway_controller(payment_gateway): gateway = frappe.get_doc("Payment Gateway", payment_gateway) if gateway.gateway_controller is None: try: - return frappe.get_doc("{0} Settings".format(payment_gateway)) + return frappe.get_doc(f"{payment_gateway} Settings") except Exception: frappe.throw(_("{0} Settings not found").format(payment_gateway)) else: @@ -116,7 +115,7 @@ def get_payment_gateway_controller(payment_gateway): def get_checkout_url(**kwargs): try: if kwargs.get("payment_gateway"): - doc = frappe.get_doc("{0} Settings".format(kwargs.get("payment_gateway"))) + doc = frappe.get_doc("{} Settings".format(kwargs.get("payment_gateway"))) return doc.get_payment_url(**kwargs) else: raise Exception diff --git a/frappe/middlewares.py b/frappe/middlewares.py index cd47b7210f..168d129ebe 100644 --- a/frappe/middlewares.py +++ b/frappe/middlewares.py @@ -13,7 +13,7 @@ from frappe.utils import cstr, get_site_name class StaticDataMiddleware(SharedDataMiddleware): def __call__(self, environ, start_response): self.environ = environ - return super(StaticDataMiddleware, self).__call__(environ, start_response) + return super().__call__(environ, start_response) def get_directory_loader(self, directory): def loader(path): diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 8e417bb45c..d3e7656d6d 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -2,7 +2,6 @@ # License: MIT. See LICENSE import datetime import json -from typing import Dict, List import frappe from frappe import _, _dict @@ -59,9 +58,7 @@ def get_controller(doctype): module_path, classname = import_path.rsplit(".", 1) module = frappe.get_module(module_path) if not hasattr(module, classname): - raise ImportError( - "{0}: {1} does not exist in module {2}".format(doctype, classname, module_path) - ) + raise ImportError(f"{doctype}: {classname} does not exist in module {module_path}") else: module = load_doctype_module(doctype, module_name) classname = doctype.replace(" ", "").replace("-", "") @@ -86,7 +83,7 @@ def get_controller(doctype): return site_controllers[doctype] -class BaseDocument(object): +class BaseDocument: _reserved_keywords = { "doctype", "meta", @@ -300,7 +297,7 @@ class BaseDocument(object): def get_valid_dict( self, sanitize=True, convert_dates_to_str=False, ignore_nulls=False, ignore_virtual=False - ) -> Dict: + ) -> dict: d = _dict() for fieldname in self.meta.get_valid_columns(): # column is valid, we can use getattr @@ -382,7 +379,7 @@ class BaseDocument(object): if key not in self.__dict__: self.__dict__[key] = None - def get_valid_columns(self) -> List[str]: + def get_valid_columns(self) -> list[str]: if self.doctype not in frappe.local.valid_columns: if self.doctype in DOCTYPES_FOR_DOCTYPE: from frappe.model.meta import get_table_columns @@ -412,7 +409,7 @@ class BaseDocument(object): no_default_fields=False, convert_dates_to_str=False, no_child_table_fields=False, - ) -> Dict: + ) -> dict: doc = self.get_valid_dict(convert_dates_to_str=convert_dates_to_str, ignore_nulls=no_nulls) doc["doctype"] = self.doctype @@ -694,7 +691,7 @@ class BaseDocument(object): if self.get("parentfield"): return "{} #{}: {}: {}".format(_("Row"), self.idx, _(df.label), docname) - return "{}: {}".format(_(df.label), docname) + return f"{_(df.label)}: {docname}" invalid_links = [] cancelled_links = [] @@ -928,7 +925,7 @@ class BaseDocument(object): if self.get("parentfield"): reference = _("{0}, Row {1}").format(_(self.doctype), self.idx) else: - reference = "{0} {1}".format(_(self.doctype), self.name) + reference = f"{_(self.doctype)} {self.name}" frappe.throw( _("{0}: '{1}' ({3}) will get truncated, as max characters allowed is {2}").format( diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 8a5becf3cc..4c62992e21 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -6,7 +6,6 @@ import copy import json import re from datetime import datetime -from typing import List, Union import frappe import frappe.defaults @@ -52,7 +51,7 @@ STRICT_UNION_PATTERN = re.compile(r".*\s(union).*\s") ORDER_GROUP_PATTERN = re.compile(r".*[^a-z0-9-_ ,`'\"\.\(\)].*") -class DatabaseQuery(object): +class DatabaseQuery: def __init__(self, doctype, user=None): self.doctype = doctype self.tables = [] @@ -98,7 +97,7 @@ class DatabaseQuery(object): pluck=None, ignore_ddl=False, parent_doctype=None, - ) -> List: + ) -> list: if ( not ignore_permissions @@ -720,7 +719,7 @@ class DatabaseQuery(object): return condition - def build_match_conditions(self, as_condition=True) -> Union[str, List]: + def build_match_conditions(self, as_condition=True) -> str | list: """add match conditions if applicable""" self.match_filters = [] self.match_conditions = [] @@ -926,7 +925,7 @@ class DatabaseQuery(object): def add_limit(self): if self.limit_page_length: - return "limit %s offset %s" % (self.limit_page_length, self.limit_start) + return f"limit {self.limit_page_length} offset {self.limit_start}" else: return "" @@ -1070,12 +1069,12 @@ def get_between_date_filter(value, df=None): to_date = add_to_date(to_date, days=1) if df and df.fieldtype == "Datetime": - data = "'%s' AND '%s'" % ( + data = "'{}' AND '{}'".format( frappe.db.format_datetime(from_date), frappe.db.format_datetime(to_date), ) else: - data = "'%s' AND '%s'" % (frappe.db.format_date(from_date), frappe.db.format_date(to_date)) + data = f"'{frappe.db.format_date(from_date)}' AND '{frappe.db.format_date(to_date)}'" return data diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index 606d3f89f1..b555dfc5dc 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -3,7 +3,6 @@ import os import shutil -from typing import List import frappe import frappe.defaults @@ -189,7 +188,7 @@ def update_naming_series(doc): revert_series_if_last(doc.meta.autoname, doc.name, doc) -def delete_from_table(doctype: str, name: str, ignore_doctypes: List[str], doc): +def delete_from_table(doctype: str, name: str, ignore_doctypes: list[str], doc): if doctype != "DocType" and doctype == name: frappe.db.delete("Singles", {"doctype": name}) else: @@ -339,7 +338,7 @@ def check_if_doc_is_dynamically_linked(doc, method="Delete"): reference_doctype = refdoc.parenttype if meta.istable else df.parent reference_docname = refdoc.parent if meta.istable else refdoc.name - at_position = "at Row: {0}".format(refdoc.idx) if meta.istable else "" + at_position = f"at Row: {refdoc.idx}" if meta.istable else "" raise_link_exists_exception(doc, reference_doctype, reference_docname, at_position) @@ -432,7 +431,7 @@ def insert_feed(doc): "doctype": "Comment", "comment_type": "Deleted", "reference_doctype": doc.doctype, - "subject": "{0} {1}".format(_(doc.doctype), doc.name), + "subject": f"{_(doc.doctype)} {doc.name}", "full_name": get_fullname(doc.owner), } ).insert(ignore_permissions=True) diff --git a/frappe/model/docfield.py b/frappe/model/docfield.py index 195385a2e1..c54a3855cb 100644 --- a/frappe/model/docfield.py +++ b/frappe/model/docfield.py @@ -45,7 +45,7 @@ def update_parent_field(f, new): if f["fieldtype"] in frappe.model.table_fields: frappe.db.begin() frappe.db.sql( - """update `tab%s` set parentfield=%s where parentfield=%s""" % (f["options"], "%s", "%s"), + """update `tab{}` set parentfield={} where parentfield={}""".format(f["options"], "%s", "%s"), (new, f["fieldname"]), ) frappe.db.commit() @@ -56,7 +56,7 @@ def get_change_column_query(f, new): desc = frappe.db.sql("desc `tab%s`" % f["parent"]) for d in desc: if d[0] == f["fieldname"]: - return "alter table `tab%s` change `%s` `%s` %s" % (f["parent"], f["fieldname"], new, d[1]) + return "alter table `tab{}` change `{}` `{}` {}".format(f["parent"], f["fieldname"], new, d[1]) def supports_translation(fieldtype): diff --git a/frappe/model/document.py b/frappe/model/document.py index 898c40861c..9b781b1999 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -3,7 +3,6 @@ import hashlib import json import time -from typing import List from werkzeug.exceptions import NotFound @@ -112,7 +111,7 @@ class Document(BaseDocument): if kwargs: # init base document - super(Document, self).__init__(kwargs) + super().__init__(kwargs) self.init_child_tables() self.init_valid_columns() @@ -136,7 +135,7 @@ class Document(BaseDocument): single_doc["name"] = self.doctype del single_doc["__islocal"] - super(Document, self).__init__(single_doc) + super().__init__(single_doc) self.init_valid_columns() self._fix_numeric_types() @@ -149,7 +148,7 @@ class Document(BaseDocument): _("{0} {1} not found").format(_(self.doctype), self.name), frappe.DoesNotExistError ) - super(Document, self).__init__(d) + super().__init__(d) for df in self._get_table_fields(): # Make sure not to query the DB for a child table, if it is a virtual one. @@ -401,9 +400,9 @@ class Document(BaseDocument): if rows: # select rows that do not match the ones in the document deleted_rows = frappe.db.sql( - """select name from `tab{0}` where parent=%s + """select name from `tab{}` where parent=%s and parenttype=%s and parentfield=%s - and name not in ({1})""".format( + and name not in ({})""".format( df.options, ",".join(["%s"] * len(rows)) ), [self.name, self.doctype, fieldname] + rows, @@ -756,7 +755,7 @@ class Document(BaseDocument): conflict = True else: tmp = frappe.db.sql( - """select modified, docstatus from `tab{0}` + """select modified, docstatus from `tab{}` where name = %s for update""".format( self.doctype ), @@ -779,7 +778,7 @@ class Document(BaseDocument): if conflict: frappe.msgprint( _("Error: Document has been modified after you have opened it") - + (" (%s, %s). " % (modified, self.modified)) + + (f" ({modified}, {self.modified}). ") + _("Please refresh to get the latest document."), raise_exception=frappe.TimestampMismatchError, ) @@ -874,7 +873,7 @@ class Document(BaseDocument): raise frappe.MandatoryError( "[{doctype}, {name}]: {fields}".format( - fields=", ".join((each[0] for each in missing)), doctype=self.doctype, name=self.name + fields=", ".join(each[0] for each in missing), doctype=self.doctype, name=self.name ) ) @@ -890,14 +889,14 @@ class Document(BaseDocument): cancelled_links.extend(result[1]) if invalid_links: - msg = ", ".join((each[2] for each in invalid_links)) + msg = ", ".join(each[2] for each in invalid_links) frappe.throw(_("Could not find {0}").format(msg), frappe.LinkValidationError) if cancelled_links: - msg = ", ".join((each[2] for each in cancelled_links)) + msg = ", ".join(each[2] for each in cancelled_links) frappe.throw(_("Cannot link cancelled document: {0}").format(msg), frappe.CancelledLinkError) - def get_all_children(self, parenttype=None) -> List["Document"]: + def get_all_children(self, parenttype=None) -> list["Document"]: """Returns all children documents from **Table** type fields in a list.""" children = [] @@ -1268,7 +1267,7 @@ class Document(BaseDocument): def is_whitelisted(self, method_name): method = getattr(self, method_name, None) if not method: - raise NotFound("Method {0} not found".format(method_name)) + raise NotFound(f"Method {method_name} not found") is_whitelisted(getattr(method, "__func__", method)) diff --git a/frappe/model/mapper.py b/frappe/model/mapper.py index 59f211e322..9df79ef276 100644 --- a/frappe/model/mapper.py +++ b/frappe/model/mapper.py @@ -231,7 +231,7 @@ def map_fetch_fields(target_doc, df, no_copy_fields): linked_doc = None # options should be like "link_fieldname.fieldname_in_liked_doc" - for fetch_df in target_doc.meta.get("fields", {"fetch_from": "^{0}.".format(df.fieldname)}): + for fetch_df in target_doc.meta.get("fields", {"fetch_from": f"^{df.fieldname}."}): if not (fetch_df.fieldtype == "Read Only" or fetch_df.read_only): continue diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 9f5c2e7611..014dd5faf1 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -17,7 +17,6 @@ Example: import json import os from datetime import datetime -from typing import List import click @@ -42,7 +41,7 @@ from frappe.modules import load_doctype_module from frappe.utils import cast, cint, cstr -def get_meta(doctype, cached=True): +def get_meta(doctype, cached=True) -> "Meta": if cached: if not frappe.local.meta_cache.get(doctype): meta = frappe.cache().hget("meta", doctype) @@ -68,7 +67,7 @@ def get_table_columns(doctype): def load_doctype_from_file(doctype): fname = frappe.scrub(doctype) - with open(frappe.get_app_path("frappe", "core", "doctype", fname, fname + ".json"), "r") as f: + with open(frappe.get_app_path("frappe", "core", "doctype", fname, fname + ".json")) as f: txt = json.loads(f.read()) for d in txt.get("fields", []): @@ -104,19 +103,19 @@ class Meta(Document): def __init__(self, doctype): self._fields = {} if isinstance(doctype, dict): - super(Meta, self).__init__(doctype) + super().__init__(doctype) elif isinstance(doctype, Document): - super(Meta, self).__init__(doctype.as_dict()) + super().__init__(doctype.as_dict()) self.process() else: - super(Meta, self).__init__("DocType", doctype) + super().__init__("DocType", doctype) self.process() def load_from_db(self): try: - super(Meta, self).load_from_db() + super().load_from_db() except frappe.DoesNotExistError: if self.doctype == "DocType" and self.name in self.special_doctypes: self.__dict__.update(load_doctype_from_file(self.name)) @@ -347,7 +346,7 @@ class Meta(Document): def get_workflow(self): return get_workflow_name(self.name) - def get_naming_series_options(self) -> List[str]: + def get_naming_series_options(self) -> list[str]: """Get list naming series options.""" field = self.get_field("naming_series") @@ -434,7 +433,7 @@ class Meta(Document): # set the fields in order if specified # order is saved as `links_order` - order = json.loads(self.get("{}_order".format(fieldname)) or "[]") + order = json.loads(self.get(f"{fieldname}_order") or "[]") if order: name_map = {d.name: d for d in self.get(fieldname)} new_list = [] diff --git a/frappe/model/naming.py b/frappe/model/naming.py index b674b0cd81..f7dbe23548 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -2,7 +2,7 @@ # License: MIT. See LICENSE import re -from typing import TYPE_CHECKING, Callable, List, Optional, Union +from typing import TYPE_CHECKING, Callable, Optional import frappe from frappe import _ @@ -81,13 +81,16 @@ class NamingSeries: return prefix - def get_preview(self, doc=None) -> List[str]: + def get_preview(self, doc=None) -> list[str]: """Generate preview of naming series without using DB counters""" generated_names = [] for count in range(1, 4): def fake_counter(_prefix, digits): - return str(count).zfill(digits) + # ignore B023: binding `count` is not necessary because + # function is evaluated immediately and it can not be done + # because of function signature requirement + return str(count).zfill(digits) # noqa: B023 generated_names.append(parse_naming_series(self.series, doc=doc, number_generator=fake_counter)) return generated_names @@ -271,10 +274,10 @@ def make_autoname(key="", doctype="", doc=""): def parse_naming_series( - parts: Union[List[str], str], + parts: list[str] | str, doctype=None, doc: Optional["Document"] = None, - number_generator: Optional[Callable[[str, int], str]] = None, + number_generator: Callable[[str, int], str] | None = None, ) -> str: """Parse the naming series and get next name. @@ -410,7 +413,7 @@ def revert_series_if_last(key, name, doc=None): frappe.db.sql("UPDATE `tabSeries` SET `current` = `current` - 1 WHERE `name`=%s", prefix) -def get_default_naming_series(doctype: str) -> Optional[str]: +def get_default_naming_series(doctype: str) -> str | None: """get default value for `naming_series` property""" naming_series_options = frappe.get_meta(doctype).get_naming_series_options() @@ -421,7 +424,7 @@ def get_default_naming_series(doctype: str) -> Optional[str]: return option -def validate_name(doctype: str, name: Union[int, str], case: Optional[str] = None): +def validate_name(doctype: str, name: int | str, case: str | None = None): if not name: frappe.throw(_("No Name Specified for {0}").format(doctype)) @@ -450,7 +453,7 @@ def validate_name(doctype: str, name: Union[int, str], case: Optional[str] = Non special_characters = "<>" if re.findall(f"[{special_characters}]+", name): - message = ", ".join("'{0}'".format(c) for c in special_characters) + message = ", ".join(f"'{c}'" for c in special_characters) frappe.throw( _("Name cannot contain special characters like {0}").format(message), frappe.NameError ) @@ -464,7 +467,7 @@ def append_number_if_name_exists(doctype, value, fieldname="name", separator="-" filters.update({fieldname: value}) exists = frappe.db.exists(doctype, filters) - regex = "^{value}{separator}\\d+$".format(value=re.escape(value), separator=separator) + regex = f"^{re.escape(value)}{separator}\\d+$" if exists: last = frappe.db.sql( @@ -482,7 +485,7 @@ def append_number_if_name_exists(doctype, value, fieldname="name", separator="-" else: count = "1" - value = "{0}{1}{2}".format(value, separator, count) + value = f"{value}{separator}{count}" return value diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index 652703aed5..2a04ee7e11 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -1,10 +1,7 @@ # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE -try: - from types import NoneType -except ImportError: - NoneType = type(None) -from typing import TYPE_CHECKING, Dict, List, Optional +from types import NoneType +from typing import TYPE_CHECKING import frappe from frappe import _, bold @@ -26,8 +23,8 @@ def update_document_title( *, doctype: str, docname: str, - title: Optional[str] = None, - name: Optional[str] = None, + title: str | None = None, + name: str | None = None, merge: bool = False, enqueue: bool = False, **kwargs, @@ -110,8 +107,8 @@ def update_document_title( def rename_doc( - doctype: Optional[str] = None, - old: Optional[str] = None, + doctype: str | None = None, + old: str | None = None, new: str = None, force: bool = False, merge: bool = False, @@ -119,7 +116,7 @@ def rename_doc( ignore_if_exists: bool = False, show_alert: bool = True, rebuild_search: bool = True, - doc: Optional[Document] = None, + doc: Document | None = None, validate: bool = True, ) -> str: """Rename a doc(dt, old) to doc(dt, new) and update all linked fields of type "Link". @@ -257,7 +254,7 @@ def update_assignments(old: str, new: str, doctype: str) -> None: frappe.db.set_value(doctype, new, "_assign", frappe.as_json(unique_assignments, indent=0)) -def update_user_settings(old: str, new: str, link_fields: List[Dict]) -> None: +def update_user_settings(old: str, new: str, link_fields: list[dict]) -> None: """ Update the user settings of all the linked doctypes while renaming. """ @@ -416,7 +413,7 @@ def update_child_docs(old: str, new: str, meta: "Meta") -> None: frappe.qb.update(df.options).set("parent", new).where(Field("parent") == old).run() -def update_link_field_values(link_fields: List[Dict], old: str, new: str, doctype: str) -> None: +def update_link_field_values(link_fields: list[dict], old: str, new: str, doctype: str) -> None: for field in link_fields: if field["issingle"]: try: @@ -452,7 +449,7 @@ def update_link_field_values(link_fields: List[Dict], old: str, new: str, doctyp field["parent"] = new -def get_link_fields(doctype: str) -> List[Dict]: +def get_link_fields(doctype: str) -> list[dict]: # get link fields from tabDocField if not frappe.flags.link_fields: frappe.flags.link_fields = {} @@ -523,7 +520,7 @@ def update_options_for_fieldtype(fieldtype: str, old: str, new: str) -> None: ).run() -def get_select_fields(old: str, new: str) -> List[Dict]: +def get_select_fields(old: str, new: str) -> list[dict]: """ get select type fields where doctype's name is hardcoded as new line separated list @@ -650,8 +647,8 @@ def rename_dynamic_links(doctype: str, old: str, new: str): def bulk_rename( - doctype: str, rows: Optional[List[List]] = None, via_console: bool = False -) -> Optional[List[str]]: + doctype: str, rows: list[list] | None = None, via_console: bool = False +) -> list[str] | None: """Bulk rename documents :param doctype: DocType to be renamed @@ -692,7 +689,7 @@ def bulk_rename( def update_linked_doctypes( - doctype: str, docname: str, linked_to: str, value: str, ignore_doctypes: Optional[List] = None + doctype: str, docname: str, linked_to: str, value: str, ignore_doctypes: list | None = None ) -> None: from frappe.model.utils.rename_doc import update_linked_doctypes @@ -708,8 +705,8 @@ def update_linked_doctypes( def get_fetch_fields( - doctype: str, linked_to: str, ignore_doctypes: Optional[List] = None -) -> List[Dict]: + doctype: str, linked_to: str, ignore_doctypes: list | None = None +) -> list[dict]: from frappe.model.utils.rename_doc import get_fetch_fields show_deprecation_warning("get_fetch_fields") diff --git a/frappe/model/sync.py b/frappe/model/sync.py index 93b883cda6..df3999054a 100644 --- a/frappe/model/sync.py +++ b/frappe/model/sync.py @@ -84,7 +84,7 @@ def sync_for(app_name, force=0, reset_permissions=False): frappe.db.commit() # show progress bar - update_progress_bar("Updating DocTypes for {0}".format(app_name), i, l) + update_progress_bar(f"Updating DocTypes for {app_name}", i, l) # print each progress bar on new line print() diff --git a/frappe/model/utils/__init__.py b/frappe/model/utils/__init__.py index 6385b61c38..351b19c8eb 100644 --- a/frappe/model/utils/__init__.py +++ b/frappe/model/utils/__init__.py @@ -47,7 +47,7 @@ def set_field_property(filters, key, value): for d in docs: d.get("fields", filters)[0].set(key, value) d.save() - print("Updated {0}".format(d.name)) + print(f"Updated {d.name}") frappe.db.commit() @@ -70,7 +70,7 @@ def render_include(content): for path in paths: app, app_path = path.split("/", 1) - with io.open(frappe.get_app_path(app, app_path), "r", encoding="utf-8") as f: + with open(frappe.get_app_path(app, app_path), encoding="utf-8") as f: include = f.read() if path.endswith(".html"): include = html_to_js_template(path, include) diff --git a/frappe/model/utils/link_count.py b/frappe/model/utils/link_count.py index 25dfe58139..9a7694b9f8 100644 --- a/frappe/model/utils/link_count.py +++ b/frappe/model/utils/link_count.py @@ -42,7 +42,7 @@ def update_link_count(): if key[0] not in ignore_doctypes: try: frappe.db.sql( - "update `tab{0}` set idx = idx + {1} where name=%s".format(key[0], count), + f"update `tab{key[0]}` set idx = idx + {count} where name=%s", key[1], auto_commit=1, ) diff --git a/frappe/model/utils/rename_doc.py b/frappe/model/utils/rename_doc.py index 00e2d78d5f..ae6649f057 100644 --- a/frappe/model/utils/rename_doc.py +++ b/frappe/model/utils/rename_doc.py @@ -2,14 +2,13 @@ # License: MIT. See LICENSE from itertools import product -from typing import Dict, List, Optional import frappe from frappe.model.rename_doc import get_link_fields def update_linked_doctypes( - doctype: str, docname: str, linked_to: str, value: str, ignore_doctypes: Optional[List] = None + doctype: str, docname: str, linked_to: str, value: str, ignore_doctypes: list | None = None ): """ linked_doctype_info_list = list formed by get_fetch_fields() function @@ -31,8 +30,8 @@ def update_linked_doctypes( def get_fetch_fields( - doctype: str, linked_to: str, ignore_doctypes: Optional[List] = None -) -> List[Dict]: + doctype: str, linked_to: str, ignore_doctypes: list | None = None +) -> list[dict]: """ doctype = Master DocType in which the changes are being made linked_to = DocType name of the field thats being updated in Master diff --git a/frappe/model/utils/rename_field.py b/frappe/model/utils/rename_field.py index 56e69455ef..9e4fc5d84a 100644 --- a/frappe/model/utils/rename_field.py +++ b/frappe/model/utils/rename_field.py @@ -40,7 +40,7 @@ def rename_field(doctype, old_fieldname, new_fieldname): ) else: # copy field value - frappe.db.sql("""update `tab%s` set `%s`=`%s`""" % (doctype, new_fieldname, old_fieldname)) + frappe.db.sql(f"""update `tab{doctype}` set `{new_fieldname}`=`{old_fieldname}`""") update_reports(doctype, old_fieldname, new_fieldname) update_users_report_view_settings(doctype, old_fieldname, new_fieldname) diff --git a/frappe/model/utils/user_settings.py b/frappe/model/utils/user_settings.py index a6ae1a818e..c12c7e27ba 100644 --- a/frappe/model/utils/user_settings.py +++ b/frappe/model/utils/user_settings.py @@ -11,9 +11,7 @@ filter_dict = {"doctype": 0, "docfield": 1, "operator": 2, "value": 3} def get_user_settings(doctype, for_update=False): - user_settings = frappe.cache().hget( - "_user_settings", "{0}::{1}".format(doctype, frappe.session.user) - ) + user_settings = frappe.cache().hget("_user_settings", f"{doctype}::{frappe.session.user}") if user_settings is None: user_settings = frappe.db.sql( @@ -43,9 +41,7 @@ def update_user_settings(doctype, user_settings, for_update=False): current.update(user_settings) - frappe.cache().hset( - "_user_settings", "{0}::{1}".format(doctype, frappe.session.user), json.dumps(current) - ) + frappe.cache().hset("_user_settings", f"{doctype}::{frappe.session.user}", json.dumps(current)) def sync_user_settings(): @@ -103,6 +99,4 @@ def update_user_settings_data( ) # clear that user settings from the redis cache - frappe.cache().hset( - "_user_settings", "{0}::{1}".format(user_setting.doctype, user_setting.user), None - ) + frappe.cache().hset("_user_settings", f"{user_setting.doctype}::{user_setting.user}", None) diff --git a/frappe/model/workflow.py b/frappe/model/workflow.py index 96fd710d91..923fbc1b3b 100644 --- a/frappe/model/workflow.py +++ b/frappe/model/workflow.py @@ -246,15 +246,15 @@ def bulk_workflow_approval(docnames, doctype, action): except Exception as e: if not frappe.message_log: # Exception is raised manually and not from msgprint or throw - message = "{0}".format(e.__class__.__name__) + message = f"{e.__class__.__name__}" if e.args: - message += " : {0}".format(e.args[0]) + message += f" : {e.args[0]}" message_dict = {"docname": docname, "message": message} failed_transactions[docname].append(message_dict) frappe.db.rollback() frappe.log_error( - title="Workflow {0} threw an error for {1} {2}".format(action, doctype, docname), + title=f"Workflow {action} threw an error for {doctype} {docname}", reference_doctype="Workflow", reference_name=action, ) @@ -286,19 +286,19 @@ def bulk_workflow_approval(docnames, doctype, action): def print_workflow_log(messages, title, doctype, indicator): if messages.keys(): - msg = "

{0}

".format(title) + msg = f"

{title}

" for doc in messages.keys(): if len(messages[doc]): - html = "
{0}".format(frappe.utils.get_link_to_form(doctype, doc)) + html = f"
{frappe.utils.get_link_to_form(doctype, doc)}" for log in messages[doc]: if log.get("message"): - html += "
{0}
".format( + html += "
{}
".format( log.get("message") ) html += "
" else: - html = "
{0}
".format(doc) + html = f"
{doc}
" msg += html frappe.msgprint(msg, title=_("Workflow Status"), indicator=indicator, is_minimizable=True) diff --git a/frappe/modules/export_file.py b/frappe/modules/export_file.py index 8eac7a9229..e3a80d6679 100644 --- a/frappe/modules/export_file.py +++ b/frappe/modules/export_file.py @@ -113,7 +113,7 @@ def create_folder(module, dt, dn, create_init): def get_custom_module_path(module): package = frappe.db.get_value("Module Def", module, "package") if not package: - frappe.throw("Package must be set for custom Module {module}".format(module=module)) + frappe.throw(f"Package must be set for custom Module {module}") path = os.path.join(get_package_path(package), scrub(module)) if not os.path.exists(path): diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py index d39f98f966..3690da0657 100644 --- a/frappe/modules/import_file.py +++ b/frappe/modules/import_file.py @@ -109,7 +109,7 @@ def import_file_by_path( """ try: docs = read_doc_from_file(path) - except IOError: + except OSError: print(f"{path} missing") return @@ -172,14 +172,14 @@ def import_file_by_path( def read_doc_from_file(path): doc = None if os.path.exists(path): - with open(path, "r") as f: + with open(path) as f: try: doc = json.loads(f.read()) except ValueError: - print("bad json: {0}".format(path)) + print(f"bad json: {path}") raise else: - raise IOError("%s missing" % path) + raise OSError("%s missing" % path) return doc @@ -254,7 +254,7 @@ def load_code_properties(doc, path): for key, extn in doc.get_code_fields().items(): codefile = os.path.join(dirname, filename.split(".")[0] + "." + extn) if os.path.exists(codefile): - with open(codefile, "r") as txtfile: + with open(codefile) as txtfile: doc.set(key, txtfile.read()) @@ -285,6 +285,6 @@ def reset_tree_properties(doc): # "rgt". They are automatically set and kept up-to-date. Importing them # would destroy any existing tree structure. if getattr(doc.meta, "is_tree", None) and any([doc.lft, doc.rgt]): - print('Ignoring values of `lft` and `rgt` for {} "{}"'.format(doc.doctype, doc.name)) + print(f'Ignoring values of `lft` and `rgt` for {doc.doctype} "{doc.name}"') doc.lft = None doc.rgt = None diff --git a/frappe/modules/patch_handler.py b/frappe/modules/patch_handler.py index ae6d9a6de2..f389312a4f 100644 --- a/frappe/modules/patch_handler.py +++ b/frappe/modules/patch_handler.py @@ -38,7 +38,6 @@ import configparser import time from enum import Enum from textwrap import dedent, indent -from typing import List, Optional import frappe @@ -52,7 +51,7 @@ class PatchType(Enum): post_model_sync = "post_model_sync" -def run_all(skip_failing: bool = False, patch_type: Optional[PatchType] = None) -> None: +def run_all(skip_failing: bool = False, patch_type: PatchType | None = None) -> None: """run all pending patches""" executed = set(frappe.get_all("Patch Log", fields="patch", pluck="patch")) @@ -81,7 +80,7 @@ def run_all(skip_failing: bool = False, patch_type: Optional[PatchType] = None) run_patch(patch) -def get_all_patches(patch_type: Optional[PatchType] = None) -> List[str]: +def get_all_patches(patch_type: PatchType | None = None) -> list[str]: if patch_type and not isinstance(patch_type, PatchType): frappe.throw(f"Unsupported patch type specified: {patch_type}") @@ -93,7 +92,7 @@ def get_all_patches(patch_type: Optional[PatchType] = None) -> List[str]: return patches -def get_patches_from_app(app: str, patch_type: Optional[PatchType] = None) -> List[str]: +def get_patches_from_app(app: str, patch_type: PatchType | None = None) -> list[str]: """Get patches from an app's patches.txt patches.txt can be: diff --git a/frappe/modules/utils.py b/frappe/modules/utils.py index ad6a75e900..f4a386cfc9 100644 --- a/frappe/modules/utils.py +++ b/frappe/modules/utils.py @@ -105,7 +105,7 @@ def sync_customizations(app=None): if os.path.exists(folder): for fname in os.listdir(folder): if fname.endswith(".json"): - with open(os.path.join(folder, fname), "r") as f: + with open(os.path.join(folder, fname)) as f: data = json.loads(f.read()) if data.get("sync_on_migrate"): sync_customizations_for_doctype(data, folder) @@ -164,7 +164,7 @@ def sync_customizations_for_doctype(data, folder): if data.get("custom_perms"): sync("custom_perms", "Custom DocPerm", "parent") - print("Updating customizations for {0}".format(doctype)) + print(f"Updating customizations for {doctype}") validate_fields_for_doctype(doctype) if update_schema and not frappe.db.get_value("DocType", doctype, "issingle"): @@ -317,7 +317,6 @@ def make_boilerplate(template, doc, opts=None): with open(target_file_path, "w") as target: with open( os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype), "boilerplate", template), - "r", ) as source: target.write( frappe.as_unicode( diff --git a/frappe/monitor.py b/frappe/monitor.py index 74f9e06ef3..e151944b1f 100644 --- a/frappe/monitor.py +++ b/frappe/monitor.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE diff --git a/frappe/parallel_test_runner.py b/frappe/parallel_test_runner.py index 4fd03773ef..39a00235cb 100644 --- a/frappe/parallel_test_runner.py +++ b/frappe/parallel_test_runner.py @@ -83,7 +83,7 @@ class ParallelTestRunner: test_record_filename = re.sub("^test_", "", filename).replace(".py", ".json") test_record_file_path = os.path.join(path, test_record_filename) if os.path.exists(test_record_file_path): - with open(test_record_file_path, "r") as f: + with open(test_record_file_path) as f: doc = json.loads(f.read()) doctype = doc["name"] make_test_records(doctype, commit=True) diff --git a/frappe/patches/v10_0/increase_single_table_column_length.py b/frappe/patches/v10_0/increase_single_table_column_length.py index 21b5a790ab..0b8e94a3f7 100644 --- a/frappe/patches/v10_0/increase_single_table_column_length.py +++ b/frappe/patches/v10_0/increase_single_table_column_length.py @@ -6,4 +6,4 @@ import frappe def execute(): for col in ("field", "doctype"): - frappe.db.sql_ddl("alter table `tabSingles` modify column `{0}` varchar(255)".format(col)) + frappe.db.sql_ddl(f"alter table `tabSingles` modify column `{col}` varchar(255)") diff --git a/frappe/patches/v11_0/delete_duplicate_user_permissions.py b/frappe/patches/v11_0/delete_duplicate_user_permissions.py index b986c6f825..f2ca6d51fe 100644 --- a/frappe/patches/v11_0/delete_duplicate_user_permissions.py +++ b/frappe/patches/v11_0/delete_duplicate_user_permissions.py @@ -13,7 +13,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 {0}""".format( + where allow=%s and user=%s and for_value=%s limit {}""".format( record.count - 1 ), (record.allow, record.user, record.for_value), diff --git a/frappe/patches/v11_0/drop_column_apply_user_permissions.py b/frappe/patches/v11_0/drop_column_apply_user_permissions.py index bfc4aee72c..0a0091624e 100644 --- a/frappe/patches/v11_0/drop_column_apply_user_permissions.py +++ b/frappe/patches/v11_0/drop_column_apply_user_permissions.py @@ -8,7 +8,7 @@ def execute(): for doctype in to_remove: if frappe.db.table_exists(doctype): if column in frappe.db.get_table_columns(doctype): - frappe.db.sql("alter table `tab{0}` drop column {1}".format(doctype, column)) + frappe.db.sql(f"alter table `tab{doctype}` drop column {column}") frappe.reload_doc("core", "doctype", "docperm", force=True) frappe.reload_doc("core", "doctype", "custom_docperm", force=True) diff --git a/frappe/patches/v11_0/fix_order_by_in_reports_json.py b/frappe/patches/v11_0/fix_order_by_in_reports_json.py index 3dfec0954f..4e955a338b 100644 --- a/frappe/patches/v11_0/fix_order_by_in_reports_json.py +++ b/frappe/patches/v11_0/fix_order_by_in_reports_json.py @@ -28,8 +28,8 @@ def execute(): sort_by = parts[1].split(" ") - json_data["order_by"] = "`tab{0}`.`{1}`".format(doc.ref_doctype, sort_by[0]) - json_data["order_by"] += " {0}".format(sort_by[1]) if len(sort_by) > 1 else "" + json_data["order_by"] = f"`tab{doc.ref_doctype}`.`{sort_by[0]}`" + json_data["order_by"] += f" {sort_by[1]}" if len(sort_by) > 1 else "" doc.json = json.dumps(json_data) doc.save() diff --git a/frappe/patches/v11_0/update_list_user_settings.py b/frappe/patches/v11_0/update_list_user_settings.py index 146b29346c..5209b9e384 100644 --- a/frappe/patches/v11_0/update_list_user_settings.py +++ b/frappe/patches/v11_0/update_list_user_settings.py @@ -13,7 +13,7 @@ def execute(): # get user_settings for each user settings = frappe.db.sql( "select * from `__UserSettings` \ - where user={0}".format( + where user={}".format( frappe.db.escape(user.user) ), as_dict=True, diff --git a/frappe/patches/v12_0/delete_duplicate_indexes.py b/frappe/patches/v12_0/delete_duplicate_indexes.py index 96ebd237d8..1cb94ca50c 100644 --- a/frappe/patches/v12_0/delete_duplicate_indexes.py +++ b/frappe/patches/v12_0/delete_duplicate_indexes.py @@ -41,10 +41,10 @@ def execute(): # build drop index query for (table_name, index_list) in final_deletion_map.items(): query_list = [] - alter_query = "ALTER TABLE `{}`".format(table_name) + alter_query = f"ALTER TABLE `{table_name}`" for index in index_list: - query_list.append("{} DROP INDEX `{}`".format(alter_query, index)) + query_list.append(f"{alter_query} DROP INDEX `{index}`") for query in query_list: try: diff --git a/frappe/patches/v12_0/fix_public_private_files.py b/frappe/patches/v12_0/fix_public_private_files.py index e1ad2f1862..382e3c2db1 100644 --- a/frappe/patches/v12_0/fix_public_private_files.py +++ b/frappe/patches/v12_0/fix_public_private_files.py @@ -30,7 +30,7 @@ def generate_file(file_name): file_doc.file_url = new_doc.file_url file_doc.save() - except IOError: + except OSError: pass except Exception as e: print(e) diff --git a/frappe/patches/v12_0/move_timeline_links_to_dynamic_links.py b/frappe/patches/v12_0/move_timeline_links_to_dynamic_links.py index 2207edd958..4d2061c5ac 100644 --- a/frappe/patches/v12_0/move_timeline_links_to_dynamic_links.py +++ b/frappe/patches/v12_0/move_timeline_links_to_dynamic_links.py @@ -22,7 +22,7 @@ def execute(): if communication.timeline_doctype and communication.timeline_name: name += 1 values.append( - """({0}, "{1}", "timeline_links", "Communication", "{2}", "{3}", "{4}", "{5}", "{6}", "{7}")""".format( + """({}, "{}", "timeline_links", "Communication", "{}", "{}", "{}", "{}", "{}", "{}")""".format( counter, str(name), frappe.db.escape(communication.name), @@ -37,7 +37,7 @@ def execute(): if communication.link_doctype and communication.link_name: name += 1 values.append( - """({0}, "{1}", "timeline_links", "Communication", "{2}", "{3}", "{4}", "{5}", "{6}", "{7}")""".format( + """({}, "{}", "timeline_links", "Communication", "{}", "{}", "{}", "{}", "{}", "{}")""".format( counter, str(name), frappe.db.escape(communication.name), @@ -55,7 +55,7 @@ def execute(): INSERT INTO `tabCommunication Link` (`idx`, `name`, `parentfield`, `parenttype`, `parent`, `link_doctype`, `link_name`, `creation`, `modified`, `modified_by`) - VALUES {0} + VALUES {} """.format( ", ".join([d for d in values]) ) diff --git a/frappe/patches/v12_0/set_correct_url_in_files.py b/frappe/patches/v12_0/set_correct_url_in_files.py index dca42a3c04..fee0b5d6fc 100644 --- a/frappe/patches/v12_0/set_correct_url_in_files.py +++ b/frappe/patches/v12_0/set_correct_url_in_files.py @@ -30,12 +30,10 @@ def execute(): if file_is_private: public_file_url = os.path.join(public_file_path, file_name) if os.path.exists(public_file_url): - frappe.db.set_value( - "File", file.name, {"file_url": "/files/{0}".format(file_name), "is_private": 0} - ) + frappe.db.set_value("File", file.name, {"file_url": f"/files/{file_name}", "is_private": 0}) else: private_file_url = os.path.join(private_file_path, file_name) if os.path.exists(private_file_url): frappe.db.set_value( - "File", file.name, {"file_url": "/private/files/{0}".format(file_name), "is_private": 1} + "File", file.name, {"file_url": f"/private/files/{file_name}", "is_private": 1} ) diff --git a/frappe/patches/v12_0/setup_tags.py b/frappe/patches/v12_0/setup_tags.py index 46482a102b..6bff8d3dac 100644 --- a/frappe/patches/v12_0/setup_tags.py +++ b/frappe/patches/v12_0/setup_tags.py @@ -17,7 +17,7 @@ def execute(): continue for _user_tags in frappe.db.sql( - "select `name`, `_user_tags` from `tab{0}`".format(doctype.name), as_dict=True + f"select `name`, `_user_tags` from `tab{doctype.name}`", as_dict=True ): if not _user_tags.get("_user_tags"): continue diff --git a/frappe/patches/v13_0/set_unique_for_page_view.py b/frappe/patches/v13_0/set_unique_for_page_view.py index 1a674f6697..45351afdde 100644 --- a/frappe/patches/v13_0/set_unique_for_page_view.py +++ b/frappe/patches/v13_0/set_unique_for_page_view.py @@ -4,6 +4,4 @@ import frappe def execute(): frappe.reload_doc("website", "doctype", "web_page_view", force=True) site_url = frappe.utils.get_site_url(frappe.local.site) - frappe.db.sql( - """UPDATE `tabWeb Page View` set is_unique=1 where referrer LIKE '%{0}%'""".format(site_url) - ) + frappe.db.sql(f"""UPDATE `tabWeb Page View` set is_unique=1 where referrer LIKE '%{site_url}%'""") diff --git a/frappe/patches/v14_0/copy_mail_data.py b/frappe/patches/v14_0/copy_mail_data.py index 6b976ba6fb..c44b7c9e92 100644 --- a/frappe/patches/v14_0/copy_mail_data.py +++ b/frappe/patches/v14_0/copy_mail_data.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/frappe/patches/v14_0/update_color_names_in_kanban_board_column.py b/frappe/patches/v14_0/update_color_names_in_kanban_board_column.py index f8d6f236cd..b568151273 100644 --- a/frappe/patches/v14_0/update_color_names_in_kanban_board_column.py +++ b/frappe/patches/v14_0/update_color_names_in_kanban_board_column.py @@ -1,7 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals import frappe diff --git a/frappe/permissions.py b/frappe/permissions.py index 55a7c0e5f3..5e56071123 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import copy -from typing import List import frappe import frappe.share @@ -421,7 +420,7 @@ def get_roles(user=None, with_standard=True): # filter standard if required if not with_standard: - roles = filter(lambda x: x not in ["All", "Guest", "Administrator"], roles) + roles = [r for r in roles if r not in ["All", "Guest", "Administrator"]] return roles @@ -516,7 +515,7 @@ def clear_user_permissions_for_doctype(doctype, user=None): def can_import(doctype, raise_exception=False): if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "import")): if raise_exception: - raise frappe.PermissionError("You are not allowed to import: {doctype}".format(doctype=doctype)) + raise frappe.PermissionError(f"You are not allowed to import: {doctype}") else: return False return True @@ -606,7 +605,7 @@ def reset_perms(doctype): frappe.db.delete("Custom DocPerm", {"parent": doctype}) -def get_linked_doctypes(dt: str) -> List: +def get_linked_doctypes(dt: str) -> list: meta = frappe.get_meta(dt) linked_doctypes = [dt] + [ d.options diff --git a/frappe/printing/doctype/letter_head/test_letter_head.py b/frappe/printing/doctype/letter_head/test_letter_head.py index 9357d15315..75019ce275 100644 --- a/frappe/printing/doctype/letter_head/test_letter_head.py +++ b/frappe/printing/doctype/letter_head/test_letter_head.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/printing/doctype/print_format/print_format.py b/frappe/printing/doctype/print_format/print_format.py index 2e12fdb8d8..e49db67512 100644 --- a/frappe/printing/doctype/print_format/print_format.py +++ b/frappe/printing/doctype/print_format/print_format.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/printing/doctype/print_heading/print_heading.py b/frappe/printing/doctype/print_heading/print_heading.py index c905e68d47..9daee06f03 100644 --- a/frappe/printing/doctype/print_heading/print_heading.py +++ b/frappe/printing/doctype/print_heading/print_heading.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/printing/doctype/print_heading/test_print_heading.py b/frappe/printing/doctype/print_heading/test_print_heading.py index 02eddb072f..74ff7ce74f 100644 --- a/frappe/printing/doctype/print_heading/test_print_heading.py +++ b/frappe/printing/doctype/print_heading/test_print_heading.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/printing/doctype/print_settings/print_settings.py b/frappe/printing/doctype/print_settings/print_settings.py index f52d08e6ec..36eaac2e68 100644 --- a/frappe/printing/doctype/print_settings/print_settings.py +++ b/frappe/printing/doctype/print_settings/print_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/printing/doctype/print_settings/test_print_settings.py b/frappe/printing/doctype/print_settings/test_print_settings.py index ba22df4438..6a6437bf97 100644 --- a/frappe/printing/doctype/print_settings/test_print_settings.py +++ b/frappe/printing/doctype/print_settings/test_print_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/printing/doctype/print_style/print_style.py b/frappe/printing/doctype/print_style/print_style.py index 00de829deb..2b0fbfe929 100644 --- a/frappe/printing/doctype/print_style/print_style.py +++ b/frappe/printing/doctype/print_style/print_style.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and contributors # License: MIT. See LICENSE diff --git a/frappe/printing/doctype/print_style/test_print_style.py b/frappe/printing/doctype/print_style/test_print_style.py index ad2b61cc87..f8ce54b9bb 100644 --- a/frappe/printing/doctype/print_style/test_print_style.py +++ b/frappe/printing/doctype/print_style/test_print_style.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies and Contributors # License: MIT. See LICENSE import unittest diff --git a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.py b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.py index 668be8d05a..d54624aaef 100644 --- a/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.py +++ b/frappe/printing/page/print_format_builder_beta/print_format_builder_beta.py @@ -1,7 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals import functools @@ -13,7 +12,7 @@ def get_google_fonts(): return _get_google_fonts() -@functools.lru_cache() +@functools.lru_cache def _get_google_fonts(): file_path = frappe.get_app_path("frappe", "data", "google_fonts.json") return frappe.parse_json(frappe.read_file(file_path)) diff --git a/frappe/public/css/bootstrap.css b/frappe/public/css/bootstrap.css index 16afe3cd54..d4ce177bae 100644 --- a/frappe/public/css/bootstrap.css +++ b/frappe/public/css/bootstrap.css @@ -259,799 +259,6 @@ th { border: 1px solid #ddd; } } -@font-face { - font-family: 'Glyphicons Halflings'; - - src: url('/assets/frappe/css/fonts/glyphicons/glyphicons-halflings-regular.eot'); - src: url('/assets/frappe/css/fonts/glyphicons/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('/assets/frappe/css/fonts/glyphicons/glyphicons-halflings-regular.woff2') format('woff2'), url('/assets/frappe/css/fonts/glyphicons/glyphicons-halflings-regular.woff') format('woff'), url('/assets/frappe/css/fonts/glyphicons/glyphicons-halflings-regular.ttf') format('truetype'), url('/assets/frappe/css/fonts/glyphicons/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); -} -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.glyphicon-asterisk:before { - content: "\2a"; -} -.glyphicon-plus:before { - content: "\2b"; -} -.glyphicon-euro:before, -.glyphicon-eur:before { - content: "\20ac"; -} -.glyphicon-minus:before { - content: "\2212"; -} -.glyphicon-cloud:before { - content: "\2601"; -} -.glyphicon-envelope:before { - content: "\2709"; -} -.glyphicon-pencil:before { - content: "\270f"; -} -.glyphicon-glass:before { - content: "\e001"; -} -.glyphicon-music:before { - content: "\e002"; -} -.glyphicon-search:before { - content: "\e003"; -} -.glyphicon-heart:before { - content: "\e005"; -} -.glyphicon-star:before { - content: "\e006"; -} -.glyphicon-star-empty:before { - content: "\e007"; -} -.glyphicon-user:before { - content: "\e008"; -} -.glyphicon-film:before { - content: "\e009"; -} -.glyphicon-th-large:before { - content: "\e010"; -} -.glyphicon-th:before { - content: "\e011"; -} -.glyphicon-th-list:before { - content: "\e012"; -} -.glyphicon-ok:before { - content: "\e013"; -} -.glyphicon-remove:before { - content: "\e014"; -} -.glyphicon-zoom-in:before { - content: "\e015"; -} -.glyphicon-zoom-out:before { - content: "\e016"; -} -.glyphicon-off:before { - content: "\e017"; -} -.glyphicon-signal:before { - content: "\e018"; -} -.glyphicon-cog:before { - content: "\e019"; -} -.glyphicon-trash:before { - content: "\e020"; -} -.glyphicon-home:before { - content: "\e021"; -} -.glyphicon-file:before { - content: "\e022"; -} -.glyphicon-time:before { - content: "\e023"; -} -.glyphicon-road:before { - content: "\e024"; -} -.glyphicon-download-alt:before { - content: "\e025"; -} -.glyphicon-download:before { - content: "\e026"; -} -.glyphicon-upload:before { - content: "\e027"; -} -.glyphicon-inbox:before { - content: "\e028"; -} -.glyphicon-play-circle:before { - content: "\e029"; -} -.glyphicon-repeat:before { - content: "\e030"; -} -.glyphicon-refresh:before { - content: "\e031"; -} -.glyphicon-list-alt:before { - content: "\e032"; -} -.glyphicon-lock:before { - content: "\e033"; -} -.glyphicon-flag:before { - content: "\e034"; -} -.glyphicon-headphones:before { - content: "\e035"; -} -.glyphicon-volume-off:before { - content: "\e036"; -} -.glyphicon-volume-down:before { - content: "\e037"; -} -.glyphicon-volume-up:before { - content: "\e038"; -} -.glyphicon-qrcode:before { - content: "\e039"; -} -.glyphicon-barcode:before { - content: "\e040"; -} -.glyphicon-tag:before { - content: "\e041"; -} -.glyphicon-tags:before { - content: "\e042"; -} -.glyphicon-book:before { - content: "\e043"; -} -.glyphicon-bookmark:before { - content: "\e044"; -} -.glyphicon-print:before { - content: "\e045"; -} -.glyphicon-camera:before { - content: "\e046"; -} -.glyphicon-font:before { - content: "\e047"; -} -.glyphicon-bold:before { - content: "\e048"; -} -.glyphicon-italic:before { - content: "\e049"; -} -.glyphicon-text-height:before { - content: "\e050"; -} -.glyphicon-text-width:before { - content: "\e051"; -} -.glyphicon-align-left:before { - content: "\e052"; -} -.glyphicon-align-center:before { - content: "\e053"; -} -.glyphicon-align-right:before { - content: "\e054"; -} -.glyphicon-align-justify:before { - content: "\e055"; -} -.glyphicon-list:before { - content: "\e056"; -} -.glyphicon-indent-left:before { - content: "\e057"; -} -.glyphicon-indent-right:before { - content: "\e058"; -} -.glyphicon-facetime-video:before { - content: "\e059"; -} -.glyphicon-picture:before { - content: "\e060"; -} -.glyphicon-map-marker:before { - content: "\e062"; -} -.glyphicon-adjust:before { - content: "\e063"; -} -.glyphicon-tint:before { - content: "\e064"; -} -.glyphicon-edit:before { - content: "\e065"; -} -.glyphicon-share:before { - content: "\e066"; -} -.glyphicon-check:before { - content: "\e067"; -} -.glyphicon-move:before { - content: "\e068"; -} -.glyphicon-step-backward:before { - content: "\e069"; -} -.glyphicon-fast-backward:before { - content: "\e070"; -} -.glyphicon-backward:before { - content: "\e071"; -} -.glyphicon-play:before { - content: "\e072"; -} -.glyphicon-pause:before { - content: "\e073"; -} -.glyphicon-stop:before { - content: "\e074"; -} -.glyphicon-forward:before { - content: "\e075"; -} -.glyphicon-fast-forward:before { - content: "\e076"; -} -.glyphicon-step-forward:before { - content: "\e077"; -} -.glyphicon-eject:before { - content: "\e078"; -} -.glyphicon-chevron-left:before { - content: "\e079"; -} -.glyphicon-chevron-right:before { - content: "\e080"; -} -.glyphicon-plus-sign:before { - content: "\e081"; -} -.glyphicon-minus-sign:before { - content: "\e082"; -} -.glyphicon-remove-sign:before { - content: "\e083"; -} -.glyphicon-ok-sign:before { - content: "\e084"; -} -.glyphicon-question-sign:before { - content: "\e085"; -} -.glyphicon-info-sign:before { - content: "\e086"; -} -.glyphicon-screenshot:before { - content: "\e087"; -} -.glyphicon-remove-circle:before { - content: "\e088"; -} -.glyphicon-ok-circle:before { - content: "\e089"; -} -.glyphicon-ban-circle:before { - content: "\e090"; -} -.glyphicon-arrow-left:before { - content: "\e091"; -} -.glyphicon-arrow-right:before { - content: "\e092"; -} -.glyphicon-arrow-up:before { - content: "\e093"; -} -.glyphicon-arrow-down:before { - content: "\e094"; -} -.glyphicon-share-alt:before { - content: "\e095"; -} -.glyphicon-resize-full:before { - content: "\e096"; -} -.glyphicon-resize-small:before { - content: "\e097"; -} -.glyphicon-exclamation-sign:before { - content: "\e101"; -} -.glyphicon-gift:before { - content: "\e102"; -} -.glyphicon-leaf:before { - content: "\e103"; -} -.glyphicon-fire:before { - content: "\e104"; -} -.glyphicon-eye-open:before { - content: "\e105"; -} -.glyphicon-eye-close:before { - content: "\e106"; -} -.glyphicon-warning-sign:before { - content: "\e107"; -} -.glyphicon-plane:before { - content: "\e108"; -} -.glyphicon-calendar:before { - content: "\e109"; -} -.glyphicon-random:before { - content: "\e110"; -} -.glyphicon-comment:before { - content: "\e111"; -} -.glyphicon-magnet:before { - content: "\e112"; -} -.glyphicon-chevron-up:before { - content: "\e113"; -} -.glyphicon-chevron-down:before { - content: "\e114"; -} -.glyphicon-retweet:before { - content: "\e115"; -} -.glyphicon-shopping-cart:before { - content: "\e116"; -} -.glyphicon-folder-close:before { - content: "\e117"; -} -.glyphicon-folder-open:before { - content: "\e118"; -} -.glyphicon-resize-vertical:before { - content: "\e119"; -} -.glyphicon-resize-horizontal:before { - content: "\e120"; -} -.glyphicon-hdd:before { - content: "\e121"; -} -.glyphicon-bullhorn:before { - content: "\e122"; -} -.glyphicon-bell:before { - content: "\e123"; -} -.glyphicon-certificate:before { - content: "\e124"; -} -.glyphicon-thumbs-up:before { - content: "\e125"; -} -.glyphicon-thumbs-down:before { - content: "\e126"; -} -.glyphicon-hand-right:before { - content: "\e127"; -} -.glyphicon-hand-left:before { - content: "\e128"; -} -.glyphicon-hand-up:before { - content: "\e129"; -} -.glyphicon-hand-down:before { - content: "\e130"; -} -.glyphicon-circle-arrow-right:before { - content: "\e131"; -} -.glyphicon-circle-arrow-left:before { - content: "\e132"; -} -.glyphicon-circle-arrow-up:before { - content: "\e133"; -} -.glyphicon-circle-arrow-down:before { - content: "\e134"; -} -.glyphicon-globe:before { - content: "\e135"; -} -.glyphicon-wrench:before { - content: "\e136"; -} -.glyphicon-tasks:before { - content: "\e137"; -} -.glyphicon-filter:before { - content: "\e138"; -} -.glyphicon-briefcase:before { - content: "\e139"; -} -.glyphicon-fullscreen:before { - content: "\e140"; -} -.glyphicon-dashboard:before { - content: "\e141"; -} -.glyphicon-paperclip:before { - content: "\e142"; -} -.glyphicon-heart-empty:before { - content: "\e143"; -} -.glyphicon-link:before { - content: "\e144"; -} -.glyphicon-phone:before { - content: "\e145"; -} -.glyphicon-pushpin:before { - content: "\e146"; -} -.glyphicon-usd:before { - content: "\e148"; -} -.glyphicon-gbp:before { - content: "\e149"; -} -.glyphicon-sort:before { - content: "\e150"; -} -.glyphicon-sort-by-alphabet:before { - content: "\e151"; -} -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152"; -} -.glyphicon-sort-by-order:before { - content: "\e153"; -} -.glyphicon-sort-by-order-alt:before { - content: "\e154"; -} -.glyphicon-sort-by-attributes:before { - content: "\e155"; -} -.glyphicon-sort-by-attributes-alt:before { - content: "\e156"; -} -.glyphicon-unchecked:before { - content: "\e157"; -} -.glyphicon-expand:before { - content: "\e158"; -} -.glyphicon-collapse-down:before { - content: "\e159"; -} -.glyphicon-collapse-up:before { - content: "\e160"; -} -.glyphicon-log-in:before { - content: "\e161"; -} -.glyphicon-flash:before { - content: "\e162"; -} -.glyphicon-log-out:before { - content: "\e163"; -} -.glyphicon-new-window:before { - content: "\e164"; -} -.glyphicon-record:before { - content: "\e165"; -} -.glyphicon-save:before { - content: "\e166"; -} -.glyphicon-open:before { - content: "\e167"; -} -.glyphicon-saved:before { - content: "\e168"; -} -.glyphicon-import:before { - content: "\e169"; -} -.glyphicon-export:before { - content: "\e170"; -} -.glyphicon-send:before { - content: "\e171"; -} -.glyphicon-floppy-disk:before { - content: "\e172"; -} -.glyphicon-floppy-saved:before { - content: "\e173"; -} -.glyphicon-floppy-remove:before { - content: "\e174"; -} -.glyphicon-floppy-save:before { - content: "\e175"; -} -.glyphicon-floppy-open:before { - content: "\e176"; -} -.glyphicon-credit-card:before { - content: "\e177"; -} -.glyphicon-transfer:before { - content: "\e178"; -} -.glyphicon-cutlery:before { - content: "\e179"; -} -.glyphicon-header:before { - content: "\e180"; -} -.glyphicon-compressed:before { - content: "\e181"; -} -.glyphicon-earphone:before { - content: "\e182"; -} -.glyphicon-phone-alt:before { - content: "\e183"; -} -.glyphicon-tower:before { - content: "\e184"; -} -.glyphicon-stats:before { - content: "\e185"; -} -.glyphicon-sd-video:before { - content: "\e186"; -} -.glyphicon-hd-video:before { - content: "\e187"; -} -.glyphicon-subtitles:before { - content: "\e188"; -} -.glyphicon-sound-stereo:before { - content: "\e189"; -} -.glyphicon-sound-dolby:before { - content: "\e190"; -} -.glyphicon-sound-5-1:before { - content: "\e191"; -} -.glyphicon-sound-6-1:before { - content: "\e192"; -} -.glyphicon-sound-7-1:before { - content: "\e193"; -} -.glyphicon-copyright-mark:before { - content: "\e194"; -} -.glyphicon-registration-mark:before { - content: "\e195"; -} -.glyphicon-cloud-download:before { - content: "\e197"; -} -.glyphicon-cloud-upload:before { - content: "\e198"; -} -.glyphicon-tree-conifer:before { - content: "\e199"; -} -.glyphicon-tree-deciduous:before { - content: "\e200"; -} -.glyphicon-cd:before { - content: "\e201"; -} -.glyphicon-save-file:before { - content: "\e202"; -} -.glyphicon-open-file:before { - content: "\e203"; -} -.glyphicon-level-up:before { - content: "\e204"; -} -.glyphicon-copy:before { - content: "\e205"; -} -.glyphicon-paste:before { - content: "\e206"; -} -.glyphicon-alert:before { - content: "\e209"; -} -.glyphicon-equalizer:before { - content: "\e210"; -} -.glyphicon-king:before { - content: "\e211"; -} -.glyphicon-queen:before { - content: "\e212"; -} -.glyphicon-pawn:before { - content: "\e213"; -} -.glyphicon-bishop:before { - content: "\e214"; -} -.glyphicon-knight:before { - content: "\e215"; -} -.glyphicon-baby-formula:before { - content: "\e216"; -} -.glyphicon-tent:before { - content: "\26fa"; -} -.glyphicon-blackboard:before { - content: "\e218"; -} -.glyphicon-bed:before { - content: "\e219"; -} -.glyphicon-apple:before { - content: "\f8ff"; -} -.glyphicon-erase:before { - content: "\e221"; -} -.glyphicon-hourglass:before { - content: "\231b"; -} -.glyphicon-lamp:before { - content: "\e223"; -} -.glyphicon-duplicate:before { - content: "\e224"; -} -.glyphicon-piggy-bank:before { - content: "\e225"; -} -.glyphicon-scissors:before { - content: "\e226"; -} -.glyphicon-bitcoin:before { - content: "\e227"; -} -.glyphicon-yen:before { - content: "\00a5"; -} -.glyphicon-ruble:before { - content: "\20bd"; -} -.glyphicon-scale:before { - content: "\e230"; -} -.glyphicon-ice-lolly:before { - content: "\e231"; -} -.glyphicon-ice-lolly-tasted:before { - content: "\e232"; -} -.glyphicon-education:before { - content: "\e233"; -} -.glyphicon-option-horizontal:before { - content: "\e234"; -} -.glyphicon-option-vertical:before { - content: "\e235"; -} -.glyphicon-menu-hamburger:before { - content: "\e236"; -} -.glyphicon-modal-window:before { - content: "\e237"; -} -.glyphicon-oil:before { - content: "\e238"; -} -.glyphicon-grain:before { - content: "\e239"; -} -.glyphicon-sunglasses:before { - content: "\e240"; -} -.glyphicon-text-size:before { - content: "\e241"; -} -.glyphicon-text-color:before { - content: "\e242"; -} -.glyphicon-text-background:before { - content: "\e243"; -} -.glyphicon-object-align-top:before { - content: "\e244"; -} -.glyphicon-object-align-bottom:before { - content: "\e245"; -} -.glyphicon-object-align-horizontal:before { - content: "\e246"; -} -.glyphicon-object-align-left:before { - content: "\e247"; -} -.glyphicon-object-align-vertical:before { - content: "\e248"; -} -.glyphicon-object-align-right:before { - content: "\e249"; -} -.glyphicon-triangle-right:before { - content: "\e250"; -} -.glyphicon-triangle-left:before { - content: "\e251"; -} -.glyphicon-triangle-bottom:before { - content: "\e252"; -} -.glyphicon-triangle-top:before { - content: "\e253"; -} -.glyphicon-console:before { - content: "\e254"; -} -.glyphicon-superscript:before { - content: "\e255"; -} -.glyphicon-subscript:before { - content: "\e256"; -} -.glyphicon-menu-left:before { - content: "\e257"; -} -.glyphicon-menu-right:before { - content: "\e258"; -} -.glyphicon-menu-down:before { - content: "\e259"; -} -.glyphicon-menu-up:before { - content: "\e260"; -} * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; diff --git a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.eot b/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a4953ff..0000000000 Binary files a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.svg b/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.svg deleted file mode 100644 index 94fb5490a2..0000000000 --- a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.ttf b/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc609a..0000000000 Binary files a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.woff b/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.woff deleted file mode 100644 index 9e612858f8..0000000000 Binary files a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.woff2 b/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b54c3..0000000000 Binary files a/frappe/public/css/fonts/glyphicons/glyphicons-halflings-regular.woff2 and /dev/null differ diff --git a/frappe/public/css/fonts/inter/LICENSE.txt b/frappe/public/css/fonts/inter/LICENSE.txt new file mode 100644 index 0000000000..65ec0f9103 --- /dev/null +++ b/frappe/public/css/fonts/inter/LICENSE.txt @@ -0,0 +1,94 @@ +Copyright (c) 2016-2020 The Inter Project Authors. +"Inter" is trademark of Rasmus Andersson. +https://github.com/rsms/inter + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/frappe/public/images/chat/wallpaper-default.jpg b/frappe/public/images/chat/wallpaper-default.jpg deleted file mode 100644 index b7818e9bf0..0000000000 Binary files a/frappe/public/images/chat/wallpaper-default.jpg and /dev/null differ diff --git a/frappe/public/images/chat/wallpaper-primary.jpg b/frappe/public/images/chat/wallpaper-primary.jpg deleted file mode 100644 index 125fff145d..0000000000 Binary files a/frappe/public/images/chat/wallpaper-primary.jpg and /dev/null differ diff --git a/frappe/public/images/help/style-settings-help.png b/frappe/public/images/help/style-settings-help.png deleted file mode 100644 index cc49373b59..0000000000 Binary files a/frappe/public/images/help/style-settings-help.png and /dev/null differ diff --git a/frappe/public/js/frappe-web.bundle.js b/frappe/public/js/frappe-web.bundle.js index b8d4006090..a3bac55e23 100644 --- a/frappe/public/js/frappe-web.bundle.js +++ b/frappe/public/js/frappe-web.bundle.js @@ -1,7 +1,6 @@ import "./jquery-bootstrap"; import "./frappe/class.js"; import "./frappe/polyfill.js"; -import "./lib/md5.min.js"; import "./lib/moment.js"; import "./frappe/provide.js"; import "./frappe/format.js"; diff --git a/frappe/public/js/frappe/form/controls/base_control.js b/frappe/public/js/frappe/form/controls/base_control.js index f491fb1427..73831d493b 100644 --- a/frappe/public/js/frappe/form/controls/base_control.js +++ b/frappe/public/js/frappe/form/controls/base_control.js @@ -226,13 +226,16 @@ frappe.ui.form.Control = class BaseControl { } } set_model_value(value) { - if(this.frm) { + if (this.frm) { this.last_value = value; return frappe.model.set_value(this.doctype, this.docname, this.df.fieldname, value, this.df.fieldtype); } else { - if(this.doc) { + if (this.doc) { this.doc[this.df.fieldname] = value; + } else { + // case where input is rendered on dialog where doc is not maintained + this.value = value; } this.set_input(value); return Promise.resolve(); diff --git a/frappe/public/js/frappe/form/controls/geolocation.js b/frappe/public/js/frappe/form/controls/geolocation.js index 688e7da3e0..527000562c 100644 --- a/frappe/public/js/frappe/form/controls/geolocation.js +++ b/frappe/public/js/frappe/form/controls/geolocation.js @@ -202,14 +202,14 @@ frappe.ui.form.ControlGeolocation = class ControlGeolocation extends frappe.ui.f get required_libs() { return [ - "assets/frappe/js/lib/leaflet/easy-button.css", - "assets/frappe/js/lib/leaflet/L.Control.Locate.css", - "assets/frappe/js/lib/leaflet/leaflet.draw.css", + "assets/frappe/js/lib/leaflet_easy_button/easy-button.css", + "assets/frappe/js/lib/leaflet_control_locate/L.Control.Locate.css", + "assets/frappe/js/lib/leaflet_draw/leaflet.draw.css", "assets/frappe/js/lib/leaflet/leaflet.css", "assets/frappe/js/lib/leaflet/leaflet.js", - "assets/frappe/js/lib/leaflet/easy-button.js", - "assets/frappe/js/lib/leaflet/leaflet.draw.js", - "assets/frappe/js/lib/leaflet/L.Control.Locate.js", + "assets/frappe/js/lib/leaflet_easy_button/easy-button.js", + "assets/frappe/js/lib/leaflet_draw/leaflet.draw.js", + "assets/frappe/js/lib/leaflet_control_locate/L.Control.Locate.js", ]; } }; diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index ebaf36fe4e..77affc7d27 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -315,7 +315,7 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat let last_value = me.last_value || ""; let last_label = me.label || ""; - if (value !== last_value || label !== last_label) { + if (value !== last_value) { me.parse_validate_and_set_in_model(value, null, label); } }); diff --git a/frappe/public/js/frappe/form/footer/form_timeline.js b/frappe/public/js/frappe/form/footer/form_timeline.js index 203859a144..0e7403d8b3 100644 --- a/frappe/public/js/frappe/form/footer/form_timeline.js +++ b/frappe/public/js/frappe/form/footer/form_timeline.js @@ -103,20 +103,34 @@ class FormTimeline extends BaseTimeline { set_document_info() { // TODO: handle creation via automation - let creation_message = __("{0} created this {1}", [ - this.get_user_link(this.frm.doc.owner), - comment_when(this.frm.doc.creation) - ]); + const creation = comment_when(this.frm.doc.creation); + let creation_message = + frappe.utils.is_current_user(this.frm.doc.owner) + ? __("You created this {0}", [creation], "Form timeline") + : __("{0} created this {1}", + [ + this.get_user_link(this.frm.doc.owner), + creation + ], + "Form timeline" + ); - let modified_message = __("{0} edited this {1}", [ - this.get_user_link(this.frm.doc.modified_by), - comment_when(this.frm.doc.modified), - ]); + const modified = comment_when(this.frm.doc.modified); + let modified_message = + frappe.utils.is_current_user(this.frm.doc.modified_by) + ? __("You edited this {0}", [modified], "Form timeline") + : __("{0} edited this {1}", + [ + this.get_user_link(this.frm.doc.modified_by), + modified + ], + "Form timeline" + ); if (this.frm.doc.route && cint(frappe.boot.website_tracking_enabled)) { let route = this.frm.doc.route; frappe.utils.get_page_view_count(route).then((res) => { - let page_view_count_message = __('{0} Page views', [res.message]); + let page_view_count_message = __('{0} Page views', [res.message], "Form timeline"); this.add_timeline_item({ content: `${creation_message} • ${modified_message} • ${page_view_count_message}`, hide_timestamp: true @@ -150,23 +164,28 @@ class FormTimeline extends BaseTimeline { } get_user_link(user) { - const user_display_text = ( - (frappe.session.user == user ? __("You") : frappe.user_info(user).fullname) || '' - ).bold(); + const user_display_text = (frappe.user_info(user).fullname || '').bold(); return frappe.utils.get_form_link('User', user, true, user_display_text); } get_view_timeline_contents() { let view_timeline_contents = []; (this.doc_info.views || []).forEach(view => { - let view_content = ` - - ${__("{0} viewed", [this.get_user_link(view.owner)])} - - `; + const view_time = comment_when(view.creation); + let view_message = frappe.utils.is_current_user(view.owner) + ? __("You viewed this {0}", [view_time], "Form timeline") + : __("{0} viewed this {1}", + [ + this.get_user_link(view.owner), + view_time + ], + "Form timeline" + ); + view_timeline_contents.push({ creation: view.creation, - content: view_content, + content: view_message, + hide_timestamp: true, }); }); return view_timeline_contents; diff --git a/frappe/public/js/frappe/form/sidebar/assign_to.js b/frappe/public/js/frappe/form/sidebar/assign_to.js index 71ad5b4cb2..befd5bc572 100644 --- a/frappe/public/js/frappe/form/sidebar/assign_to.js +++ b/frappe/public/js/frappe/form/sidebar/assign_to.js @@ -164,17 +164,9 @@ frappe.ui.form.AssignToDialog = class AssignToDialog { return frappe.db.get_link_options("User", txt, {user_type: "System User", enabled: 1}); } }, - { - label: __("Comment"), - fieldtype: 'Small Text', - fieldname: 'description' - }, { fieldtype: 'Section Break' }, - { - fieldtype: 'Column Break' - }, { label: __("Complete By"), fieldtype: 'Date', @@ -203,6 +195,14 @@ frappe.ui.form.AssignToDialog = class AssignToDialog { ], // Pick up priority from the source document, if it exists and is available in ToDo default: ["Low", "Medium", "High"].includes(me.frm && me.frm.doc.priority ? me.frm.doc.priority : 'Medium') + }, + { + fieldtype: 'Section Break' + }, + { + label: __("Comment"), + fieldtype: 'Small Text', + fieldname: 'description' } ]; } diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js index 606ed42444..615b73e82a 100644 --- a/frappe/public/js/frappe/socketio_client.js +++ b/frappe/public/js/frappe/socketio_client.js @@ -1,12 +1,9 @@ +import { io } from "socket.io-client"; frappe.socketio = { open_tasks: {}, open_docs: [], emit_queue: [], init: function(port = 3000) { - if (!window.io) { - return; - } - if (frappe.boot.disable_async) { return; } @@ -15,15 +12,29 @@ frappe.socketio = { return; } - //Enable secure option when using HTTPS + // Enable secure option when using HTTPS if (window.location.protocol == "https:") { - frappe.socketio.socket = io.connect(frappe.socketio.get_host(port), {secure: true}); - } - else if (window.location.protocol == "http:") { - frappe.socketio.socket = io.connect(frappe.socketio.get_host(port)); - } - else if (window.location.protocol == "file:") { - frappe.socketio.socket = io.connect(window.localStorage.server); + frappe.socketio.socket = io.connect( + frappe.socketio.get_host(port), + { + secure: true, + withCredentials: true, + } + ); + } else if (window.location.protocol == "http:") { + frappe.socketio.socket = io.connect( + frappe.socketio.get_host(port), + { + withCredentials: true, + } + ); + } else if (window.location.protocol == "file:") { + frappe.socketio.socket = io.connect( + window.localStorage.server, + { + withCredentials: true, + } + ); } if (!frappe.socketio.socket) { @@ -35,10 +46,6 @@ frappe.socketio = { frappe.msgprint(message); }); - frappe.socketio.socket.on('eval_js', function(message) { - eval(message); - }); - frappe.socketio.socket.on('progress', function(data) { if(data.progress) { data.percent = flt(data.progress[0]) / data.progress[1] * 100; diff --git a/frappe/public/js/frappe/utils/number_format.js b/frappe/public/js/frappe/utils/number_format.js index b0d66ccec5..a513d88469 100644 --- a/frappe/public/js/frappe/utils/number_format.js +++ b/frappe/public/js/frappe/utils/number_format.js @@ -122,16 +122,22 @@ window.format_number = function (v, format, decimals) { }; function format_currency(v, currency, decimals) { - var format = get_number_format(currency); - var symbol = get_currency_symbol(currency); - if(decimals === undefined) { + const format = get_number_format(currency); + const symbol = get_currency_symbol(currency); + const show_symbol_on_right = frappe.model.get_value(":Currency", currency, "symbol_on_right") ?? false; + + if (decimals === undefined) { decimals = frappe.boot.sysdefaults.currency_precision || null; } - if (symbol) + if (symbol) { + if (show_symbol_on_right) { + return format_number(v, format, decimals) + " " + __(symbol); + } return __(symbol) + " " + format_number(v, format, decimals); - else - return format_number(v, format, decimals); + } + + return format_number(v, format, decimals); } function get_currency_symbol(currency) { @@ -249,4 +255,4 @@ Object.assign(window, { remainder, round_based_on_smallest_currency_fraction, in_list -}); \ No newline at end of file +}); diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 74c89aa01a..34374d7c85 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1532,5 +1532,9 @@ Object.assign(frappe.utils, { load_video_player() { return frappe.require("video_player.bundle.js"); - } + }, + + is_current_user(user) { + return user === frappe.session.user; + }, }); diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index d5c6fb5e80..8060ea6812 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -21,6 +21,19 @@ frappe.views.TreeFactory = class TreeFactory extends frappe.views.Factory { frappe.views.trees[options.doctype] = new frappe.views.TreeView(options); }); } + + on_show() { + /** + * When the the treeview is visited using the previous button, + * the framework just show the treeview element that is hidden. + * Due to this, the data of the tree can be old. + * To deal with this, the tree will be refreshed whenever the + * treeview is visible. + */ + let route = frappe.get_route(); + let treeview = frappe.views.trees[route[1]]; + treeview && treeview.make_tree(); + } } frappe.views.TreeView = class TreeView { diff --git a/frappe/public/js/lib/Sortable.min.js b/frappe/public/js/lib/Sortable.min.js deleted file mode 100755 index 3dcf767c3a..0000000000 --- a/frappe/public/js/lib/Sortable.min.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! Sortable 1.9.0 - MIT | git://github.com/SortableJS/Sortable.git */ - -!function(t){"use strict";"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&void 0!==module.exports?module.exports=t():window.Sortable=t()}(function(){"use strict";if("undefined"==typeof window||!window.document)return function(){throw new Error("Sortable.js requires a window with a document")};function A(t,e){if(!t||!t.getBoundingClientRect)return ut();var o=t,n=!1;do{if(o.clientWidth=n.left-i&&t<=n.right+i,a=e>=n.top-i&&e<=n.bottom+i;if(i&&r&&a)return d[o]}}((t=t.touches?t.touches[0]:t).clientX,t.clientY);if(e){var o={};for(var n in t)o[n]=t[n];o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[Q]._onDragOver(o)}}}var mt;function bt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be HTMLElement, not "+{}.toString.call(t);this.el=t,this.options=e=Ot({},e),t[Q]=this;var o={group:null,sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,bubbleScroll:!0,draggable:/[uo]l/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return ht(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:D(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==bt.supportPointer&&"PointerEvent"in window,emptyInsertThreshold:5};for(var n in o)!(n in e)&&(e[n]=o[n]);for(var i in vt(e),this)"_"===i.charAt(0)&&"function"==typeof this[i]&&(this[i]=this[i].bind(this));this.nativeDraggable=!e.forceFallback&&nt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?_t(t,"pointerdown",this._onTapStart):(_t(t,"mousedown",this._onTapStart),_t(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(_t(t,"dragover",this),_t(t,"dragenter",this)),d.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[])}function wt(t,e,o,n){if(t){o=o||J;do{if(null!=e&&(">"===e[0]?t.parentNode===o&&It(t,e):It(t,e))||n&&t===o)return t;if(t===o)break}while(t=(i=t).host&&i!==J&&i.host.nodeType?i.host:i.parentNode)}var i;return null}function _t(t,e,o){t.addEventListener(e,o,!T&&h)}function yt(t,e,o){t.removeEventListener(e,o,!T&&h)}function Dt(t,e,o){if(t&&e)if(t.classList)t.classList[o?"add":"remove"](e);else{var n=(" "+t.className+" ").replace(a," ").replace(" "+e+" "," ");t.className=(n+(o?" "+e:"")).replace(a," ")}}function Tt(t,e,o){var n=t&&t.style;if(n){if(void 0===o)return J.defaultView&&J.defaultView.getComputedStyle?o=J.defaultView.getComputedStyle(t,""):t.currentStyle&&(o=t.currentStyle),void 0===e?o:o[e];e in n||-1!==e.indexOf("webkit")||(e="-webkit-"+e),n[e]=o+("string"==typeof o?"":"px")}}function St(t){var e="";do{var o=Tt(t,"transform");o&&"none"!==o&&(e=o+" "+e)}while(t=t.parentNode);return window.DOMMatrix?new DOMMatrix(e):window.WebKitCSSMatrix?new WebKitCSSMatrix(e):window.CSSMatrix?new CSSMatrix(e):void 0}function Ct(t,e,o){if(t){var n=t.getElementsByTagName(e),i=0,r=n.length;if(o)for(;i"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return!1}return!1}}function t(o,n){return function(){if(!mt){var t=arguments,e=this;mt=$(function(){1===t.length?o.call(e,t[0]):o.apply(e,t),mt=void 0},n)}}}function Ot(t,e){if(t&&e)for(var o in e)e.hasOwnProperty(o)&&(t[o]=e[o]);return t}function Ht(t){return o&&o.dom?o.dom(t).cloneNode(!0):e?e(t).clone(!0)[0]:t.cloneNode(!0)}function Bt(t){return $(t,0)}function Rt(t){return clearTimeout(t)}function Lt(t,e,o,n){if(t.getBoundingClientRect||t===y){var i,r,a,l,s,c,d;if(d=t!==y&&t!==ut()?(r=(i=t.getBoundingClientRect()).top,a=i.left,l=i.bottom,s=i.right,c=i.height,i.width):(a=r=0,l=window.innerHeight,s=window.innerWidth,c=window.innerHeight,window.innerWidth),n&&t!==y&&(o=o||t.parentNode,!T))do{if(o&&o.getBoundingClientRect&&"none"!==Tt(o,"transform")){var h=o.getBoundingClientRect();r-=h.top+D(Tt(o,"border-top-width")),a-=h.left+D(Tt(o,"border-left-width")),l=r+i.height,s=a+i.width;break}}while(o=o.parentNode);if(e&&t!==y){var u=St(o||t),f=u&&u.a,p=u&&u.d;u&&(l=(r/=p)+(c/=p),s=(a/=f)+(d/=f))}return{top:r,left:a,bottom:l,right:s,width:d,height:c}}}function Wt(t,e){for(var o=A(t,!0),n=Lt(t)[e];o;){var i=Lt(o)[e];if(!("top"===e||"left"===e?i<=n:n<=i))return o;if(o===ut())break;o=A(o,!1)}return!1}function Ft(t){var e=0,o=0,n=ut();if(t)do{var i=St(t),r=i.a,a=i.d;e+=t.scrollLeft*r,o+=t.scrollTop*a}while(t!==n&&(t=t.parentNode));return[e,o]}return bt.prototype={constructor:bt,_computeIsAligned:function(t){var e;if(p&&!it?(u(),e=J.elementFromPoint(t.clientX,t.clientY),f()):e=t.target,e=wt(e,this.options.draggable,this.el,!1),!at&&E&&E.parentNode===this.el){for(var o,n,i,r,a,l,s,c,d=this.el.children,h=0;h=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){E&&Mt(E),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;yt(t,"mouseup",this._disableDelayedDrag),yt(t,"touchend",this._disableDelayedDrag),yt(t,"touchcancel",this._disableDelayedDrag),yt(t,"mousemove",this._delayedDragTouchMoveHandler),yt(t,"touchmove",this._delayedDragTouchMoveHandler),yt(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||("touch"==t.pointerType?t:null),!this.nativeDraggable||e?this.options.supportPointer?_t(J,"pointermove",this._onTouchMove):_t(J,e?"touchmove":"mousemove",this._onTouchMove):(_t(E,"dragend",this),_t(M,"dragstart",this._onDragStart));try{J.selection?Bt(function(){J.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){if(w=!1,M&&E){this.nativeDraggable&&(_t(J,"dragover",this._handleAutoScroll),_t(J,"dragover",n));var o=this.options;!t&&Dt(E,o.dragClass,!1),Dt(E,o.ghostClass,!0),Tt(E,"transform",""),bt.active=this,t&&this._appendGhost(),Et(this,M,"start",E,M,M,P,void 0,O,void 0,e)}else this._nulling()},_emulateDragOver:function(t){if(R){if(this._lastX===R.clientX&&this._lastY===R.clientY&&!t)return;this._lastX=R.clientX,this._lastY=R.clientY,u();for(var e=J.elementFromPoint(R.clientX,R.clientY),o=e;e&&e.shadowRoot&&(e=e.shadowRoot.elementFromPoint(R.clientX,R.clientY))!==o;)o=e;if(o)do{if(o[Q])if(o[Q]._onDragOver({clientX:R.clientX,clientY:R.clientY,target:e,rootEl:o})&&!this.options.dragoverBubble)break;e=o}while(o=o.parentNode);E.parentNode[Q]._computeIsAligned(R),f()}},_onTouchMove:function(t,e){if(m){var o=this.options,n=o.fallbackTolerance,i=o.fallbackOffset,r=t.touches?t.touches[0]:t,a=p&&St(p),l=p&&a&&a.a,s=p&&a&&a.d,c=et&&b&&Ft(b),d=(r.clientX-m.clientX+i.x)/(l||1)+(c?c[0]-_[0]:0)/(l||1),h=(r.clientY-m.clientY+i.y)/(s||1)+(c?c[1]-_[1]:0)/(s||1),u=t.touches?"translate3d("+d+"px,"+h+"px,0)":"translate("+d+"px,"+h+"px)";if(!bt.active&&!w){if(n&&st(lt(r.clientX-this._lastX),lt(r.clientY-this._lastY))this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.1",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.1",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('