diff --git a/frappe/modules/utils.py b/frappe/modules/utils.py index 4fb1cfe2a1..05d6f9b6ef 100644 --- a/frappe/modules/utils.py +++ b/frappe/modules/utils.py @@ -5,8 +5,7 @@ """ import json import os -from glob import glob -from textwrap import dedent +from textwrap import dedent, indent from typing import TYPE_CHECKING, Union import frappe @@ -22,7 +21,7 @@ if TYPE_CHECKING: doctype_python_modules = {} -def export_module_json(doc: "Document", is_standard: bool, module: str) -> str: +def export_module_json(doc: "Document", is_standard: bool, module: str) -> str | None: """Make a folder for the given doc and add its json file (make it a standard object that will be synced) @@ -30,25 +29,28 @@ def export_module_json(doc: "Document", is_standard: bool, module: str) -> str: Eg: For exporting a Print Format "_Test Print Format 1", the return value will be `/home/gavin/frappe-bench/apps/frappe/frappe/core/print_format/_test_print_format_1/_test_print_format_1` """ - if is_standard and frappe.flags.in_import and frappe.get_conf().developer_mode: - return + if not frappe.flags.in_import and is_standard and frappe.get_conf().developer_mode: + from frappe.modules.export_file import export_to_files - from frappe.modules.export_file import export_to_files + # json + export_to_files( + record_list=[[doc.doctype, doc.name]], record_module=module, create_init=is_standard + ) - export_to_files( - record_list=[[doc.doctype, doc.name]], record_module=module, create_init=is_standard - ) - - return os.path.join(get_module_path(module), scrub(doc.doctype), scrub(doc.name), scrub(doc.name)) + return os.path.join( + frappe.get_module_path(module), scrub(doc.doctype), scrub(doc.name), scrub(doc.name) + ) def get_doc_module(module: str, doctype: str, name: str) -> "ModuleType": """Get custom module for given document""" - name = scrub(name) - module = scrub(module) - doctype = scrub(doctype) - app = frappe.local.module_app[module] - return frappe.get_module(f"{app}.{module}.{doctype}.{name}.{name}") + module_name = "{app}.{module}.{doctype}.{name}.{name}".format( + app=frappe.local.module_app[scrub(module)], + doctype=scrub(doctype), + module=scrub(module), + name=scrub(name), + ) + return frappe.get_module(module_name) @frappe.whitelist() @@ -58,11 +60,12 @@ def export_customizations( """Export Custom Field and Property Setter for the current document to the app folder. This will be synced with bench migrate""" + sync_on_migrate = cint(sync_on_migrate) + with_permissions = cint(with_permissions) + if not frappe.get_conf().developer_mode: frappe.throw(_("Only allowed to export customizations in developer mode")) - sync_on_migrate = cint(sync_on_migrate) - with_permissions = cint(with_permissions) custom = { "custom_fields": frappe.get_all("Custom Field", fields="*", filters={"dt": doctype}), "property_setters": frappe.get_all("Property Setter", fields="*", filters={"doc_type": doctype}), @@ -79,43 +82,38 @@ def export_customizations( # also update the custom fields and property setters for all child tables for d in frappe.get_meta(doctype).get_table_fields(): - export_customizations( - module=module, - doctype=d.options, - sync_on_migrate=sync_on_migrate, - with_permissions=with_permissions, - ) + export_customizations(module, d.options, sync_on_migrate, with_permissions) if custom["custom_fields"] or custom["property_setters"] or custom["custom_perms"]: folder_path = os.path.join(get_module_path(module), "custom") - file_path = os.path.join(folder_path, f"{scrub(doctype)}.json") + if not os.path.exists(folder_path): + os.makedirs(folder_path) - os.makedirs(folder_path, exist_ok=True) - with open(file_path, "w") as f: + path = os.path.join(folder_path, scrub(doctype) + ".json") + with open(path, "w") as f: f.write(frappe.as_json(custom)) - frappe.msgprint( - _("Customizations for {0} exported to:
{1}").format(doctype, file_path) - ) - return file_path + frappe.msgprint(_("Customizations for {0} exported to:
{1}").format(doctype, path)) -def sync_customizations(app: str | None = None): +def sync_customizations(app=None): """Sync custom fields and property setters from custom folder in each app module""" - apps = frappe.get_installed_apps() if not app else [app] + + if app: + apps = [app] + else: + apps = frappe.get_installed_apps() for app_name in apps: for module_name in frappe.local.app_modules.get(app_name) or []: - module_custom_folder = frappe.get_app_path(app_name, module_name, "custom") - if not os.path.exists(module_custom_folder): - continue - - for json_file in glob(os.path.join(module_custom_folder, "*.json")): - with open(os.path.join(module_custom_folder, json_file)) as f: - data = json.loads(f.read()) - - if data.get("sync_on_migrate"): - sync_customizations_for_doctype(data, module_custom_folder) + folder = frappe.get_app_path(app_name, module_name, "custom") + if os.path.exists(folder): + for fname in os.listdir(folder): + if fname.endswith(".json"): + 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) def sync_customizations_for_doctype(data: dict, folder: str): @@ -294,8 +292,9 @@ def make_boilerplate( base_class_import = "from frappe.utils.nestedset import NestedSet" if doc.get("is_virtual"): - controller_body = dedent( - """ + controller_body = indent( + dedent( + """ def db_insert(self): pass @@ -314,6 +313,8 @@ def make_boilerplate( def get_stats(self, args): pass """ + ), + "\t", ) with open(target_file_path, "w") as target, open(template_file_path) as source: