šŸ’ Monkey Patching and Overriding Anything in Frappe Framework (Python + JavaScript)

Customizing standard functionality in Frappe and ERPNext is often easy — hooks, events, and overrides are there for a reason.
However, there are cases where Frappe’s official extension points are not enough:

  • Some functions aren’t whitelisted.
  • Some reports don’t belong to a Doctype (so override_doctype_class won’t work).
  • Some classes are buried deep and are never exposed for hooks.

In such situations, you can still achieve full control using Monkey Patching — a powerful technique in Python and JavaScript that allows you to override any function, class, or file at runtime.

Let’s understand how you can do this, the right way, using real examples from ERPNext.


:rocket: Problem Statement: Overriding a Report (General Ledger)

Suppose you want to customize ERPNext’s General Ledger report, but:

  • You can’t override it from hooks.py because it’s not tied to a Doctype.
  • You can’t modify core files (bad practice).

Still, you want full control over both the backend (Python) and frontend (JavaScript) of the report.


:snake: Overriding Python Code via __init__.py

Here’s how to override the Python logic without touching core files:

1. Create Your Custom Python File

Path:

sudhanshu_app/custom_script/report/general_ledger/general_ledger.py

In this file:

  • Copy the original code from erpnext/accounts/report/general_ledger/general_ledger.py.
  • Modify it according to your business needs.

Example:

def execute(filters=None):
    # Your custom logic
    return custom_columns, custom_data

2. Monkey Patch via __init__.py

Path:

sudhanshu_app/custom_script/report/general_ledger/__init__.py

Write the following:

import frappe
from sudhanshu_app.custom_script.report.general_ledger.general_ledger import execute as custom_general_ledger
import erpnext.accounts.report.general_ledger.general_ledger

# Replace the original execute function with your custom one
erpnext.accounts.report.general_ledger.general_ledger.execute = custom_general_ledger

Boom! Now whenever General Ledger report is called, your version of execute runs instead of the original.

:white_check_mark: No core file touched.
:white_check_mark: Fully reversible.
:white_check_mark: Upgradable safely (with minimal merge conflicts).


:desktop_computer: Overriding JavaScript Code via hooks.py

The frontend (JavaScript) of reports is loaded dynamically in Frappe. You can override it too!

1. Create Your Custom JS File

Path:

sudhanshu_app/public/js/report/general_ledger.js

In this file:

  • Copy the full original JavaScript code from erpnext/public/js/erpnext/accounts_report/general_ledger.js (or wherever it is).
  • Make your custom changes.

Example:

frappe.query_reports["General Ledger"] = {
    "filters": [...],
    "formatter": function (value, row, column, data, default_formatter) {
        // Your custom formatter
    }
}

2. Include It in hooks.py

In your hooks.py, add:

app_include_js = [
    "/assets/sudhanshu_app/js/report/general_ledger.js"
]

This ensures your JS loads after ERPNext’s base JS and replaces the standard report behavior.


:bullseye: Key Takeaways

  • Monkey Patching gives you freedom to override any Python function, class, or method in Frappe.
  • Overriding JavaScript is as simple as copying and injecting your own custom script via hooks.py.
  • Best Practice: Always comment clearly that this is a monkey patch so your future team (or your future self) knows it’s intentional.
  • Upgrade-Proofing: Since you’re not editing core files, upgrades are relatively safe — just review changes in the original files after major updates.

:rocket: Beyond Reports: What Else Can You Override?

  • Custom whitelisted functions
  • Server scripts
  • API endpoints
  • Background jobs
  • Page controllers
  • Event handlers
  • Class methods

:high_voltage: Final Thoughts

Monkey patching gives you superpowers, but with great power comes great responsibility.

Use it carefully, transparently, and only when needed — preferably when standard hooks and extension points aren’t available.

By mastering these techniques, you can unlock full customization potential in any Frappe / ERPNext project — without ever touching the core!

24 Likes

But How I can override function get_dialog_constructor(type) that locate in /frappe/public/js/frappe/widgets/widget_dialog.js from custom app ???

you can copy whole widget_dialog.js and paste in your custom app,
make necessary changes,
and add that in app_include_js in hooks,

it will work fine

how can i use monkey patching to customize the downloaded pdf file print format for any core report like general ledger

@Sudhanshu i do like the do but it not working with me

in hooks.py

Monkey patching should not be done at all.
On multi-tenant systems (like Frappe Cloud), even sites which do not have your app installed get the overridden code.
Instead use regional overrides or introduce hooks in core ERPNext/framework to achieve the same functions.

there is scenario when we need to override Standard function. That function is not whitelisted method, nor that function is in Class. Then how to override that functions?

There might be some import issue, check we import is write, and yes you can do it in Hooks.py as well

You shouldn’t override standard methods like that. I’m pretty sure your use case could be implemented in some other way. Or you can contribute to the core with your change or add a hook to make it work - but that would require contributing to the ERPNext core product. Monkey patching is quite easy to do, and hence people misuse it a lot.

Can i use it to override core JS file of Doctype ??

yes you can