From a8427c735e97501416b565f1493928a0828c6b67 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 Nov 2020 18:01:16 +0530 Subject: [PATCH 1/4] fix: Dont take backup in dry run + other fixes --- frappe/installer.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frappe/installer.py b/frappe/installer.py index 51113beae8..9807421e98 100755 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -135,7 +135,7 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) if not confirm: return - if not no_backup: + if not (dry_run or no_backup): from frappe.utils.backups import scheduled_backup print("Backing up...") scheduled_backup(ignore_files=True) @@ -173,13 +173,15 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) if not dry_run: remove_from_installed_apps(app_name) - for doctype in set(drop_doctypes): - print("* dropping Table for '{0}'...".format(doctype)) + for doctype in set(drop_doctypes): + print("* dropping Table for '{0}'...".format(doctype)) + if not dry_run: frappe.db.sql_ddl("drop table `tab{0}`".format(doctype)) + if not dry_run: frappe.db.commit() - click.secho("Uninstalled App {0} from Site {1}".format(app_name, frappe.local.site), fg="green") + click.secho("Uninstalled App {0} from Site {1}".format(app_name, frappe.local.site), fg="green") frappe.flags.in_uninstall = False From b3a487242ff52feb6b30e94750b64d32171772f7 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 Nov 2020 18:04:44 +0530 Subject: [PATCH 2/4] fix: Use get_all instead of get_list --- frappe/installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/installer.py b/frappe/installer.py index 9807421e98..dd03783869 100755 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -147,7 +147,7 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) for module_name in modules: print("Deleting Module '{0}'".format(module_name)) - for doctype in frappe.get_list("DocType", filters={"module": module_name}, fields=["name", "issingle"]): + for doctype in frappe.get_all("DocType", filters={"module": module_name}, fields=["name", "issingle"]): print("* removing DocType '{0}'...".format(doctype.name)) if not dry_run: @@ -161,7 +161,7 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) doctypes_with_linked_modules = ordered_doctypes + [doctype.parent for doctype in linked_doctypes if doctype.parent not in ordered_doctypes] for doctype in doctypes_with_linked_modules: - for record in frappe.get_list(doctype, filters={"module": module_name}): + for record in frappe.get_all(doctype, filters={"module": module_name}): print("* removing {0} '{1}'...".format(doctype, record.name)) if not dry_run: frappe.delete_doc(doctype, record.name) From 5facf0fd1c45f812f7224d852e11ad63bbeff8c8 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 Nov 2020 18:17:54 +0530 Subject: [PATCH 3/4] style: Use f-strings, pluck and Black --- frappe/installer.py | 49 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/frappe/installer.py b/frappe/installer.py index dd03783869..7f630cbe57 100755 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -121,34 +121,41 @@ def remove_from_installed_apps(app_name): def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False): """Remove app and all linked to the app's module with the app from a site.""" import click + site = frappe.local.site # dont allow uninstall app if not installed unless forced if not force: if app_name not in frappe.get_installed_apps(): - click.secho("App {0} not installed on Site {1}".format(app_name, frappe.local.site), fg="yellow") + click.secho(f"App {app_name} not installed on Site {site}", fg="yellow") return - print("Uninstalling App {0} from Site {1}...".format(app_name, frappe.local.site)) + print(f"Uninstalling App {app_name} from Site {site}...") if not dry_run and not yes: - confirm = click.confirm("All doctypes (including custom), modules related to this app will be deleted. Are you sure you want to continue?") + confirm = click.confirm( + "All doctypes (including custom), modules related to this app will be" + " deleted. Are you sure you want to continue?" + ) if not confirm: return if not (dry_run or no_backup): from frappe.utils.backups import scheduled_backup + print("Backing up...") scheduled_backup(ignore_files=True) frappe.flags.in_uninstall = True drop_doctypes = [] - modules = (x.name for x in frappe.get_all("Module Def", filters={"app_name": app_name})) + modules = frappe.get_all("Module Def", filters={"app_name": app_name}, pluck="name") for module_name in modules: - print("Deleting Module '{0}'".format(module_name)) + print(f"Deleting Module '{module_name}'") - for doctype in frappe.get_all("DocType", filters={"module": module_name}, fields=["name", "issingle"]): - print("* removing DocType '{0}'...".format(doctype.name)) + for doctype in frappe.get_all( + "DocType", filters={"module": module_name}, fields=["name", "issingle"] + ): + print(f"* removing DocType '{doctype.name}'...") if not dry_run: frappe.delete_doc("DocType", doctype.name) @@ -156,17 +163,25 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) if not doctype.issingle: drop_doctypes.append(doctype.name) - linked_doctypes = frappe.get_all("DocField", filters={"fieldtype": "Link", "options": "Module Def"}, fields=['parent']) + linked_doctypes = frappe.get_all( + "DocField", filters={"fieldtype": "Link", "options": "Module Def"}, fields=["parent"] + ) ordered_doctypes = ["Desk Page", "Report", "Page", "Web Form"] - doctypes_with_linked_modules = ordered_doctypes + [doctype.parent for doctype in linked_doctypes if doctype.parent not in ordered_doctypes] - + all_doctypes_with_linked_modules = ordered_doctypes + [ + doctype.parent + for doctype in linked_doctypes + if doctype.parent not in ordered_doctypes + ] + doctypes_with_linked_modules = [ + x for x in all_doctypes_with_linked_modules if frappe.db.exists("DocType", x) + ] for doctype in doctypes_with_linked_modules: - for record in frappe.get_all(doctype, filters={"module": module_name}): - print("* removing {0} '{1}'...".format(doctype, record.name)) + for record in frappe.get_all(doctype, filters={"module": module_name}, pluck="name"): + print(f"* removing {doctype} '{record}'...") if not dry_run: - frappe.delete_doc(doctype, record.name) + frappe.delete_doc(doctype, record) - print("* removing Module Def '{0}'...".format(module_name)) + print(f"* removing Module Def '{module_name}'...") if not dry_run: frappe.delete_doc("Module Def", module_name) @@ -174,14 +189,14 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) remove_from_installed_apps(app_name) for doctype in set(drop_doctypes): - print("* dropping Table for '{0}'...".format(doctype)) + print(f"* dropping Table for '{doctype}'...") if not dry_run: - frappe.db.sql_ddl("drop table `tab{0}`".format(doctype)) + frappe.db.sql_ddl(f"drop table `tab{doctype}`") if not dry_run: frappe.db.commit() - click.secho("Uninstalled App {0} from Site {1}".format(app_name, frappe.local.site), fg="green") + click.secho(f"Uninstalled App {app_name} from Site {site}", fg="green") frappe.flags.in_uninstall = False From d28fb7ff5e7c74a516a9c2bf5ac44fb1535165cc Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 Nov 2020 18:37:21 +0530 Subject: [PATCH 4/4] fix: ignore on_trash, delete comment on dt --- frappe/installer.py | 11 +++++------ frappe/model/delete_doc.py | 14 ++++++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/frappe/installer.py b/frappe/installer.py index 7f630cbe57..ac411e2667 100755 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -121,6 +121,7 @@ def remove_from_installed_apps(app_name): def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False): """Remove app and all linked to the app's module with the app from a site.""" import click + site = frappe.local.site # dont allow uninstall app if not installed unless forced @@ -158,7 +159,7 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) print(f"* removing DocType '{doctype.name}'...") if not dry_run: - frappe.delete_doc("DocType", doctype.name) + frappe.delete_doc("DocType", doctype.name, ignore_on_trash=True) if not doctype.issingle: drop_doctypes.append(doctype.name) @@ -179,14 +180,11 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) for record in frappe.get_all(doctype, filters={"module": module_name}, pluck="name"): print(f"* removing {doctype} '{record}'...") if not dry_run: - frappe.delete_doc(doctype, record) + frappe.delete_doc(doctype, record, ignore_on_trash=True) print(f"* removing Module Def '{module_name}'...") if not dry_run: - frappe.delete_doc("Module Def", module_name) - - if not dry_run: - remove_from_installed_apps(app_name) + frappe.delete_doc("Module Def", module_name, ignore_on_trash=True) for doctype in set(drop_doctypes): print(f"* dropping Table for '{doctype}'...") @@ -194,6 +192,7 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False) frappe.db.sql_ddl(f"drop table `tab{doctype}`") if not dry_run: + remove_from_installed_apps(app_name) frappe.db.commit() click.secho(f"Uninstalled App {app_name} from Site {site}", fg="green") diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index a38470e3f5..862abe375c 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -335,19 +335,25 @@ def clear_timeline_references(link_doctype, link_name): WHERE `tabCommunication Link`.link_doctype=%s AND `tabCommunication Link`.link_name=%s""", (link_doctype, link_name)) def insert_feed(doc): - from frappe.utils import get_fullname - - if frappe.flags.in_install or frappe.flags.in_import or getattr(doc, "no_feed_on_delete", False): + if ( + frappe.flags.in_install + or frappe.flags.in_uninstall + or frappe.flags.in_import + or getattr(doc, "no_feed_on_delete", False) + ): return + from frappe.utils import get_fullname + frappe.get_doc({ "doctype": "Comment", "comment_type": "Deleted", "reference_doctype": doc.doctype, "subject": "{0} {1}".format(_(doc.doctype), doc.name), - "full_name": get_fullname(doc.owner) + "full_name": get_fullname(doc.owner), }).insert(ignore_permissions=True) + def delete_controllers(doctype, module): """ Delete controller code in the doctype folder