diff --git a/.github/workflows/deps-checker.yml b/.github/workflows/deps-checker.yml index 3f81b5c633..d3fa8c80fb 100644 --- a/.github/workflows/deps-checker.yml +++ b/.github/workflows/deps-checker.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: '3.10' - uses: actions/checkout@v3 - run: pip install pip-audit - run: pip-audit ${GITHUB_WORKSPACE} diff --git a/.github/workflows/docs-checker.yml b/.github/workflows/docs-checker.yml index dade810b64..e61ee6355a 100644 --- a/.github/workflows/docs-checker.yml +++ b/.github/workflows/docs-checker.yml @@ -15,7 +15,7 @@ jobs: - name: 'Setup Environment' uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: '3.10' - name: 'Clone repo' uses: actions/checkout@v3 diff --git a/.github/workflows/patch-mariadb-tests.yml b/.github/workflows/patch-mariadb-tests.yml index 8cfae52525..765d83dd4f 100644 --- a/.github/workflows/patch-mariadb-tests.yml +++ b/.github/workflows/patch-mariadb-tests.yml @@ -31,9 +31,10 @@ jobs: uses: actions/checkout@v3 - name: Setup Python - uses: actions/setup-python@v4 + uses: "gabrielfalcao/pyenv-action@v9" with: - python-version: '3.8' + versions: 3.10:latest, 3.7:latest, 2.7:latest + command: pyenv local 3.10 - name: Setup Node uses: actions/setup-node@v3 @@ -120,15 +121,23 @@ jobs: for version in $(seq 12 13) do echo "Updating to v$version" + if [ $version == 12 ]; then + pyenv local 2.7 + elif [ $version == 13 ]; then + pyenv local 3.7 + fi branch_name="version-$version-hotfix" git fetch --depth 1 upstream $branch_name:$branch_name - git checkout -q -f $branch_name - bench setup requirements --python + + rm -rf ~/frappe-bench/env + bench setup env bench --site test_site migrate done echo "Updating to last commit" git checkout -q -f "$GITHUB_SHA" - bench setup requirements --python + pyenv local 3.10 + rm -rf ~/frappe-bench/env + bench setup env bench --site test_site migrate diff --git a/.github/workflows/publish-assets-develop.yml b/.github/workflows/publish-assets-develop.yml index bd387a1c06..9219e70eb0 100644 --- a/.github/workflows/publish-assets-develop.yml +++ b/.github/workflows/publish-assets-develop.yml @@ -18,7 +18,7 @@ jobs: node-version: 14 - uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Set up bench and build assets run: | npm install -g yarn diff --git a/.github/workflows/publish-assets-releases.yml b/.github/workflows/publish-assets-releases.yml index e3f316fd57..09c87984a9 100644 --- a/.github/workflows/publish-assets-releases.yml +++ b/.github/workflows/publish-assets-releases.yml @@ -21,7 +21,7 @@ jobs: python-version: '12.x' - uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Set up bench and build assets run: | npm install -g yarn diff --git a/.github/workflows/server-mariadb-tests.yml b/.github/workflows/server-mariadb-tests.yml index a32e18ae7b..719972f535 100644 --- a/.github/workflows/server-mariadb-tests.yml +++ b/.github/workflows/server-mariadb-tests.yml @@ -42,7 +42,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Check if build should be run id: check-build diff --git a/.github/workflows/server-postgres-tests.yml b/.github/workflows/server-postgres-tests.yml index 8ff56f74f3..8f015f43e6 100644 --- a/.github/workflows/server-postgres-tests.yml +++ b/.github/workflows/server-postgres-tests.yml @@ -45,7 +45,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Check if build should be run id: check-build diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 96f3869788..421e50ebcc 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -41,7 +41,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Check if build should be run id: check-build diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index b67e915a16..0000000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -coverage==5.5 -Faker~=13.12.1 -pyngrok~=5.0.5 -unittest-xml-reporting~=3.0.4 diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index e56803acb7..a965d9c1b2 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -1298,7 +1298,7 @@ def validate_fields(meta): frappe.throw(_("Is Published Field must be a valid fieldname"), InvalidFieldNameError) def check_website_search_field(meta): - if not meta.website_search_field: + if not meta.get("website_search_field"): return if meta.website_search_field not in fieldname_list: diff --git a/frappe/core/doctype/role/role.py b/frappe/core/doctype/role/role.py index 7092004eaf..2119f3caa1 100644 --- a/frappe/core/doctype/role/role.py +++ b/frappe/core/doctype/role/role.py @@ -67,7 +67,10 @@ class Role(Document): def get_info_based_on_role(role, field="email"): """Get information of all users that have been assigned this role""" users = frappe.get_list( - "Has Role", filters={"role": role}, parent_doctype="User", fields=["parent as user_name"] + "Has Role", + filters={"role": role, "parenttype": "User"}, + parent_doctype="User", + fields=["parent as user_name"], ) return get_user_info(users, field) diff --git a/frappe/core/doctype/role/test_role.py b/frappe/core/doctype/role/test_role.py index a94796436d..44b9b1cdee 100644 --- a/frappe/core/doctype/role/test_role.py +++ b/frappe/core/doctype/role/test_role.py @@ -3,6 +3,7 @@ import unittest import frappe +from frappe.core.doctype.role.role import get_info_based_on_role test_records = frappe.get_test_records("Role") @@ -43,3 +44,11 @@ class TestUser(unittest.TestCase): role.save() user.reload() self.assertTrue(user.user_type == "Website User") + + def test_get_users_by_role(self): + + role = "System Manager" + sys_managers = get_info_based_on_role(role, field="name") + + for user in sys_managers: + self.assertIn(role, frappe.get_roles(user)) diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 3f1b60d903..22abcf9a99 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -8,6 +8,7 @@ import hashlib import hmac import json from time import sleep +from typing import Dict, Optional from urllib.parse import urlparse import requests @@ -80,8 +81,8 @@ def get_context(doc): return {"doc": doc, "utils": get_safe_globals().get("frappe").get("utils")} -def enqueue_webhook(doc, webhook): - webhook = frappe.get_doc("Webhook", webhook.get("name")) +def enqueue_webhook(doc, webhook) -> None: + webhook: Webhook = frappe.get_doc("Webhook", webhook.get("name")) headers = get_webhook_headers(doc, webhook) data = get_webhook_data(doc, webhook) @@ -98,6 +99,11 @@ def enqueue_webhook(doc, webhook): frappe.logger().debug({"webhook_success": r.text}) log_request(webhook.request_url, headers, data, r) break + + except requests.exceptions.ReadTimeout as e: + frappe.logger().debug({"webhook_error": e, "try": i + 1}) + log_request(webhook.request_url, headers, data) + except Exception as e: frappe.logger().debug({"webhook_error": e, "try": i + 1}) log_request(webhook.request_url, headers, data, r) @@ -108,7 +114,7 @@ def enqueue_webhook(doc, webhook): webhook.log_error("Webhook failed") -def log_request(url, headers, data, res): +def log_request(url: str, headers: Dict, data: Dict, res: Optional[requests.Response] = None): request_log = frappe.get_doc( { "doctype": "Webhook Request Log", diff --git a/frappe/patches.txt b/frappe/patches.txt index 66422c7db0..425468f06c 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -121,7 +121,7 @@ execute:frappe.delete_doc_if_exists('DocType', 'GCalendar Settings') frappe.patches.v12_0.remove_example_email_thread_notify execute:from frappe.desk.page.setup_wizard.install_fixtures import update_genders;update_genders() frappe.patches.v12_0.set_correct_url_in_files -execute:frappe.reload_doc('core', 'doctype', 'doctype') +execute:frappe.reload_doc('core', 'doctype', 'doctype') #2022-06-21 execute:frappe.reload_doc('custom', 'doctype', 'property_setter') frappe.patches.v13_0.remove_invalid_options_for_data_fields frappe.patches.v13_0.website_theme_custom_scss @@ -190,7 +190,6 @@ frappe.patches.v14_0.transform_todo_schema frappe.patches.v14_0.remove_post_and_post_comment frappe.patches.v14_0.reset_creation_datetime frappe.patches.v14_0.remove_is_first_startup -frappe.patches.v14_0.reload_workspace_child_tables frappe.patches.v14_0.clear_long_pending_stale_logs frappe.patches.v14_0.log_settings_migration diff --git a/frappe/patches/v14_0/reload_workspace_child_tables.py b/frappe/patches/v14_0/reload_workspace_child_tables.py deleted file mode 100644 index c22774d94c..0000000000 --- a/frappe/patches/v14_0/reload_workspace_child_tables.py +++ /dev/null @@ -1,13 +0,0 @@ -import frappe - - -def execute(): - child_tables = frappe.get_all( - "DocField", - pluck="options", - filters={"fieldtype": ["in", frappe.model.table_fields], "parent": "Workspace"}, - ) - - for child_table in child_tables: - if child_table != "Has Role": - frappe.reload_doc("desk", "doctype", child_table, force=True) diff --git a/frappe/patches/v14_0/update_workspace2.py b/frappe/patches/v14_0/update_workspace2.py index c6586f46a1..a6c9db503f 100644 --- a/frappe/patches/v14_0/update_workspace2.py +++ b/frappe/patches/v14_0/update_workspace2.py @@ -7,6 +7,16 @@ from frappe import _ def execute(): frappe.reload_doc("desk", "doctype", "workspace", force=True) + child_tables = frappe.get_all( + "DocField", + pluck="options", + filters={"fieldtype": ["in", frappe.model.table_fields], "parent": "Workspace"}, + ) + + for child_table in child_tables: + if child_table != "Has Role": + frappe.reload_doc("desk", "doctype", child_table, force=True) + for seq, workspace in enumerate(frappe.get_all("Workspace", order_by="name asc")): doc = frappe.get_doc("Workspace", workspace.name) content = create_content(doc) diff --git a/frappe/printing/page/print/print.py b/frappe/printing/page/print/print.py index 82ad22656d..baf98438cd 100644 --- a/frappe/printing/page/print/print.py +++ b/frappe/printing/page/print/print.py @@ -14,6 +14,8 @@ def get_print_settings_to_show(doctype, docname): print_settings_fields = [] for fieldname in fields: df = print_settings.meta.get_field(fieldname) + if not df: + continue df.default = print_settings.get(fieldname) print_settings_fields.append(df) diff --git a/frappe/translate.py b/frappe/translate.py index 460c7db9b0..5dbbbd31f2 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -15,7 +15,7 @@ import operator import os import re from csv import reader -from typing import List, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union from pypika.terms import PseudoColumn @@ -149,13 +149,12 @@ def set_default_language(lang): def get_lang_dict(): """Returns all languages in dict format, full name is the key e.g. `{"english":"en"}`""" - result = dict( + return dict( frappe.get_all("Language", fields=["language_name", "name"], order_by="modified", as_list=True) ) - return result -def get_dict(fortype, name=None): +def get_dict(fortype: str, name: Optional[str] = None) -> Dict: """Returns translation dict for a type of object. :param fortype: must be one of `doctype`, `page`, `report`, `include`, `jsfile`, `boot` @@ -206,7 +205,7 @@ def get_dict(fortype, name=None): translation_assets[asset_key] = message_dict cache.hset("translation_assets", frappe.local.lang, translation_assets, shared=True) - translation_map = translation_assets[asset_key] + translation_map: Dict = translation_assets[asset_key] translation_map.update(get_user_translations(frappe.local.lang)) @@ -249,13 +248,13 @@ def make_dict_from_messages(messages, full_dict=None, load_user_translation=True return out -def get_lang_js(fortype, name): +def get_lang_js(fortype: str, name: str) -> str: """Returns code snippet to be appended at the end of a JS script. :param fortype: Type of object, e.g. `DocType` :param name: Document name """ - return "\n\n$.extend(frappe._messages, %s)" % json.dumps(get_dict(fortype, name)) + return f"\n\n$.extend(frappe._messages, {json.dumps(get_dict(fortype, name))})" def get_full_dict(lang): @@ -634,10 +633,10 @@ def get_server_messages(app): inside an app""" messages = [] file_extensions = (".py", ".html", ".js", ".vue") - for basepath, folders, files in os.walk(frappe.get_pymodule_path(app)): - for dontwalk in (".git", "public", "locale"): - if dontwalk in folders: - folders.remove(dontwalk) + app_walk = os.walk(frappe.get_pymodule_path(app)) + + for basepath, folders, files in app_walk: + folders[:] = [folder for folder in folders if folder not in {".git", "__pycache__"}] for f in files: f = frappe.as_unicode(f) diff --git a/frappe/translations/pt-BR.csv b/frappe/translations/pt-BR.csv index 49c16ee634..d4dfe920ae 100644 --- a/frappe/translations/pt-BR.csv +++ b/frappe/translations/pt-BR.csv @@ -2473,7 +2473,7 @@ There should remain at least one System Manager,Não deve permanecer pelo menos There was an error saving filters,Houve um erro ao salvar os filtros, There were errors,Ocorreram erros, There were errors while creating the document. Please try again.,"Houve erros ao criar o documento. Por favor, tente novamente.", -There were errors while sending email. Please try again.,Ocorreram erros durante o envio de email. Por favor, tente novamente., +There were errors while sending email. Please try again.,"Ocorreram erros durante o envio de email. Por favor, tente novamente.", "There were some errors setting the name, please contact the administrator","Houve alguns erros de definir o nome, por favor, entre em contato com o administrador", These values will be automatically updated in transactions and also will be useful to restrict permissions for this user on transactions containing these values.,Esses valores serão atualizados automaticamente em transações e também serão úteis para restringir as permissões para este usuário em operações que contenham esses valores., Third Party Apps,Aplicativos de terceiros, diff --git a/frappe/translations/pt_br.csv b/frappe/translations/pt_br.csv index 49c16ee634..d4dfe920ae 100644 --- a/frappe/translations/pt_br.csv +++ b/frappe/translations/pt_br.csv @@ -2473,7 +2473,7 @@ There should remain at least one System Manager,Não deve permanecer pelo menos There was an error saving filters,Houve um erro ao salvar os filtros, There were errors,Ocorreram erros, There were errors while creating the document. Please try again.,"Houve erros ao criar o documento. Por favor, tente novamente.", -There were errors while sending email. Please try again.,Ocorreram erros durante o envio de email. Por favor, tente novamente., +There were errors while sending email. Please try again.,"Ocorreram erros durante o envio de email. Por favor, tente novamente.", "There were some errors setting the name, please contact the administrator","Houve alguns erros de definir o nome, por favor, entre em contato com o administrador", These values will be automatically updated in transactions and also will be useful to restrict permissions for this user on transactions containing these values.,Esses valores serão atualizados automaticamente em transações e também serão úteis para restringir as permissões para este usuário em operações que contenham esses valores., Third Party Apps,Aplicativos de terceiros, diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index de55a9b2ea..bd4cff9ef9 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -478,7 +478,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: '3.10' - name: Setup Node uses: actions/setup-node@v2 diff --git a/pyproject.toml b/pyproject.toml index 89be81eaf0..ad97b1eeea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ authors = [ { name = "Frappe Technologies Pvt Ltd", email = "developers@frappe.io"} ] description = "Metadata driven, full-stack low code web framework" -requires-python = ">=3.8" +requires-python = ">=3.10" readme = "README.md" dynamic = ["version"] dependencies = [ @@ -103,3 +103,9 @@ force_grid_wrap = 0 use_parentheses = true ensure_newline_before_comments = true indent = "\t" + +[tool.bench.dev-dependencies] +coverage = "~=6.4.1" +Faker = "~=13.12.1" +pyngrok = "~=5.0.5" +unittest-xml-reporting = "~=3.0.4"