fix: force type check in whitelisted methods (#37044)

* fix(contact): force type check in contact whitelisted methods

* fix(google_indexing): force type check in google_indexing whitelisted methods

* fix(assignment_rule): add type checks to assignment_rule whitelisted methods

* refactor: remove unused args

* fix(queue): add type hints to whitelisted methods in queue.py

* fix(auto_email_report): add type hints to whitelisted methods

* fix(dashboard): add type hints to whitelisted methods

* fix(sidebar_item_group): add type hints to whitelisted methods

* fix(weasyprint): add type hints to whitelisted methods

* fix(backups): add type hints to whitelisted methods

* fix(document_naming_settings): add type hints to whitelisted methods

* fix(get_latest_submissions): add type hints to whitelisted methods

* fix(custom_field): add type hints to whitelisted methods

* fix(customize_form): add type hints to whitelisted methods

* fix(personal_data_deletion_request): add type hints to whitelisted functions

* fix(__init__): add type hints to whitelisted methods

* fix(prepared_report): add type hints to whitelisted methods

* fix(session_default_settings): add type hints to whitelisted methods

* fix(document_follow): add type hints to whitelisted methods

* fix(route_history): add type hints to whitelisted methods

* fix(form_tour): add type hints to whitelisted methods

* fix(dashboard_settings): add type hints to whitelisted methods

* fix(address): add type hints to whitelisted methods

* fix(contact): add type hints to whitelisted methods

* fix(discussion_reply): add type hints to whitelisted methods

* fix(auto_repeat): add type hints to whitelisted methods

* fix: add the missing type hints and misc. corrections

* fix(email): add type hints to whitelisted methods

* fix(permitted_documents_for_users): add type hints to whitelisted methods

* fix: correct the type hints

* fix: int PK types

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
Co-authored-by: Ankush Menat <ankush@frappe.io>
This commit is contained in:
Aarol D'Souza 2026-02-17 20:46:30 +05:30 committed by GitHub
parent 2231252fe8
commit 9eef4f6dae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 77 additions and 42 deletions

View file

@ -199,7 +199,7 @@ def get_assignments(doc) -> list[dict]:
@frappe.whitelist()
def bulk_apply(doctype, docnames):
def bulk_apply(doctype: str, docnames: str | list[str]):
docnames = frappe.parse_json(docnames)
background = len(docnames) > 5

View file

@ -556,7 +556,13 @@ def get_auto_repeat_entries(date=None):
@frappe.whitelist()
def make_auto_repeat(doctype, docname, frequency="Daily", start_date=None, end_date=None):
def make_auto_repeat(
doctype: str,
docname: str | int,
frequency: str = "Daily",
start_date: str | None = None,
end_date: str | None = None,
):
if not start_date:
start_date = getdate(today())
doc = frappe.new_doc("Auto Repeat")
@ -573,7 +579,9 @@ def make_auto_repeat(doctype, docname, frequency="Daily", start_date=None, end_d
# method for reference_doctype filter
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_auto_repeat_doctypes(doctype, txt, searchfield, start, page_len, filters):
def get_auto_repeat_doctypes(
doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: str | dict | list
):
res = frappe.get_all(
"Property Setter",
{

View file

@ -1,6 +1,8 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
from typing import Any
import frappe
from frappe import _
@ -110,7 +112,7 @@ def delete_contact_and_address(doctype: str, docname: str) -> None:
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def filter_dynamic_link_doctypes(
doctype, txt: str, searchfield, start, page_len, filters: dict
doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict[str, Any]
) -> list[list[str]]:
from frappe.permissions import get_doctypes_with_read

View file

@ -1,6 +1,8 @@
# Copyright (c) 2015, Frappe Technologies and contributors
# License: MIT. See LICENSE
from typing import Any
from jinja2 import TemplateSyntaxError
import frappe
@ -262,7 +264,9 @@ def get_company_address(company):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def address_query(doctype, txt, searchfield, start, page_len, filters):
def address_query(
doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict[str, Any]
):
from frappe.desk.search import search_widget
_filters = []

View file

@ -1,5 +1,7 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
from typing import Any
import frappe
from frappe import _
from frappe.contacts.address_and_contact import set_link_title
@ -312,7 +314,7 @@ def invite_user(contact: str):
@frappe.whitelist()
def get_contact_details(contact):
def get_contact_details(contact: str):
contact = frappe.get_doc("Contact", contact)
contact.check_permission()
@ -341,7 +343,9 @@ def update_contact(doc, method):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def contact_query(doctype, txt, searchfield, start, page_len, filters):
def contact_query(
doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict[str, Any]
):
from frappe.desk.reportview import get_match_cond
doctype = "Contact"
@ -379,7 +383,7 @@ def contact_query(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist()
def address_query(links):
def address_query(links: str):
import json
links = [

View file

@ -174,7 +174,7 @@ class DocumentNamingSettings(Document):
NamingSeries(series).validate()
@frappe.whitelist()
def get_options(self, doctype=None):
def get_options(self, doctype: str | None = None):
doctype = doctype or self.transaction_type
if not doctype:
return

View file

@ -165,7 +165,7 @@ def update_job_id(prepared_report):
@frappe.whitelist()
def make_prepared_report(report_name, filters=None):
def make_prepared_report(report_name: str, filters: dict[str, Any] | str | list | None = None):
"""run reports in background"""
prepared_report = frappe.get_doc(
{
@ -212,7 +212,7 @@ def process_filters_for_prepared_report(filters: dict[str, Any] | str) -> str:
@frappe.whitelist()
def get_reports_in_queued_state(report_name, filters):
def get_reports_in_queued_state(report_name: str, filters: dict[str, Any] | str | list):
return frappe.get_all(
"Prepared Report",
filters={
@ -252,7 +252,7 @@ def expire_stalled_report():
@frappe.whitelist()
def delete_prepared_reports(reports):
def delete_prepared_reports(reports: str | list[dict[str, Any]]):
reports = frappe.parse_json(reports)
for report in reports:
prepared_report = frappe.get_doc("Prepared Report", report["name"])
@ -284,7 +284,7 @@ def create_json_gz_file(data, dt, dn, report_name):
@frappe.whitelist()
def download_attachment(dn):
def download_attachment(dn: str):
pr = frappe.get_doc("Prepared Report", dn)
if not pr.has_permission("read"):
frappe.throw(frappe._("Cannot Download Report due to insufficient permissions"))
@ -330,7 +330,7 @@ def has_permission(doc, user):
@frappe.whitelist()
def enqueue_json_to_csv_conversion(prepared_report_name):
def enqueue_json_to_csv_conversion(prepared_report_name: str):
"""Call this to enqueue the conversion in background."""
enqueue(method=convert_json_to_csv, queue="long", prepared_report_name=prepared_report_name)

View file

@ -2,6 +2,7 @@
# License: MIT. See LICENSE
import json
from typing import Any
import frappe
from frappe import _
@ -43,7 +44,7 @@ def get_session_default_values():
@frappe.whitelist()
def set_session_default_values(default_values):
def set_session_default_values(default_values: str | dict[str, Any]):
default_values = frappe.parse_json(default_values)
for entry in default_values:
try:

View file

@ -192,7 +192,7 @@ def queue_submission(doc: Document, action: str, alert: bool = True):
@frappe.whitelist()
def get_latest_submissions(doctype, docname):
def get_latest_submissions(doctype: str, docname: str | int):
# NOTE: not used creation as orderby intentianlly as we have used update_modified=False everywhere
# hence assuming modified will be equal to creation for submission queue documents

View file

@ -1,6 +1,8 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
from typing import Any
import frappe
import frappe.utils.user
from frappe.model import data_fieldtypes
@ -44,7 +46,9 @@ def get_columns_and_fields(doctype):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def query_doctypes(doctype, txt, searchfield, start, page_len, filters):
def query_doctypes(
doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict[str, Any]
):
user = filters.get("user")
user_perms = frappe.utils.user.UserPermissions(user)
user_perms.build_permissions()

View file

@ -269,7 +269,7 @@ class CustomField(Document):
@frappe.whitelist()
def get_fields_label(doctype=None):
def get_fields_label(doctype: str | None = None):
meta = frappe.get_meta(doctype)
if doctype in core_doctypes_list:

View file

@ -710,7 +710,7 @@ def is_standard_or_system_generated_field(df):
@frappe.whitelist()
def get_link_filters_from_doc_without_customisations(doctype, fieldname):
def get_link_filters_from_doc_without_customisations(doctype: str, fieldname: str):
"""Get the filters of a link field from a doc without customisations
In backend the customisations are not applied.
Customisations are applied in the client side.

View file

@ -85,7 +85,7 @@ def get_permission_query_conditions(user):
@frappe.whitelist()
def get_permitted_charts(dashboard_name):
def get_permitted_charts(dashboard_name: str):
permitted_charts = []
dashboard = frappe.get_doc("Dashboard", dashboard_name)
for chart in dashboard.charts:
@ -101,7 +101,7 @@ def get_permitted_charts(dashboard_name):
@frappe.whitelist()
def get_permitted_cards(dashboard_name):
def get_permitted_cards(dashboard_name: str):
dashboard = frappe.get_doc("Dashboard", dashboard_name)
return [card for card in dashboard.cards if frappe.has_permission("Number Card", doc=card.card)]

View file

@ -2,6 +2,7 @@
# License: MIT. See LICENSE
import json
from typing import Any
import frappe
@ -26,7 +27,7 @@ class DashboardSettings(Document):
@frappe.whitelist()
def create_dashboard_settings(user):
def create_dashboard_settings(user: str):
if not frappe.db.exists("Dashboard Settings", user):
doc = frappe.new_doc("Dashboard Settings")
doc.name = user
@ -43,7 +44,7 @@ def get_permission_query_conditions(user):
@frappe.whitelist()
def save_chart_config(reset, config, chart_name):
def save_chart_config(reset: int | str | bool, config: str | dict[str, Any], chart_name: str):
reset = frappe.parse_json(reset)
doc = frappe.get_doc("Dashboard Settings", frappe.session.user)
chart_config = frappe.parse_json(doc.chart_config) or {}

View file

@ -75,7 +75,7 @@ class FormTour(Document):
@frappe.whitelist()
def reset_tour(tour_name):
def reset_tour(tour_name: str):
for user in frappe.get_all("User", pluck="name"):
onboarding_status = frappe.parse_json(frappe.db.get_value("User", user, "onboarding_status"))
onboarding_status.pop(tour_name, None)
@ -88,7 +88,7 @@ def reset_tour(tour_name):
@frappe.whitelist()
def update_user_status(value, step):
def update_user_status(value: str, step: str):
from frappe.utils.telemetry import capture
step = frappe.parse_json(step)

View file

@ -1,6 +1,8 @@
# Copyright (c) 2022, Frappe Technologies and contributors
# License: MIT. See LICENSE
from typing import Any
import frappe
from frappe.deferred_insert import deferred_insert as _deferred_insert
from frappe.model.document import Document
@ -29,7 +31,7 @@ class RouteHistory(Document):
@frappe.whitelist()
def deferred_insert(routes):
def deferred_insert(routes: str | list[dict[str, Any]]):
routes = [
{
"user": frappe.session.user,

View file

@ -48,7 +48,7 @@ class SidebarItemGroup(Document):
@frappe.whitelist()
def get_reports(module_name=None):
def get_reports(module_name: str | None = None):
reports_info = []
if module_name:
sidebar_group = frappe.get_doc("Sidebar Item Group", module_name)

View file

@ -246,7 +246,7 @@ def is_document_followed(doctype, doc_name, user):
@frappe.whitelist()
def get_follow_users(doctype, doc_name):
def get_follow_users(doctype: str, doc_name: str):
return frappe.get_all(
"Document Follow", filters={"ref_doctype": doctype, "ref_docname": doc_name}, fields=["user"]
)

View file

@ -16,7 +16,7 @@ def sendmail_to_system_managers(subject, content):
@frappe.whitelist()
def get_contact_list(txt, page_length=20, extra_filters: str | None = None) -> list[dict]:
def get_contact_list(txt: str, page_length: int = 20, extra_filters: str | None = None) -> list[dict]:
"""Return email ids for a multiselect field."""
if extra_filters:
extra_filters = frappe.parse_json(extra_filters)
@ -60,7 +60,7 @@ def get_system_managers():
@frappe.whitelist()
def relink(name, reference_doctype=None, reference_name=None):
def relink(name: str, reference_doctype: str | None = None, reference_name: str | None = None):
frappe.db.sql(
"""update
`tabCommunication`
@ -77,7 +77,9 @@ def relink(name, reference_doctype=None, reference_name=None):
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_communication_doctype(doctype, txt, searchfield, start, page_len, filters):
def get_communication_doctype(
doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: str | list | dict
):
user_perms = frappe.utils.user.UserPermissions(frappe.session.user)
user_perms.build_permissions()
can_read = user_perms.can_read

View file

@ -299,7 +299,7 @@ class AutoEmailReport(Document):
@frappe.whitelist()
def download(name):
def download(name: str):
"""Download report locally"""
auto_email_report = frappe.get_doc("Auto Email Report", name)
auto_email_report.check_permission()
@ -315,7 +315,7 @@ def download(name):
@frappe.whitelist()
def send_now(name):
def send_now(name: str):
"""Send Auto Email report now"""
auto_email_report = frappe.get_doc("Auto Email Report", name)
auto_email_report.check_permission()

View file

@ -94,7 +94,7 @@ def get_unsubcribed_url(reference_doctype, reference_name, email, unsubscribe_me
@frappe.whitelist(allow_guest=True)
def unsubscribe(doctype, name, email):
def unsubscribe(doctype: str, name: str, email: str):
# unsubsribe from comments and communications
if not frappe.in_test and not verify_request():
return

View file

@ -6,7 +6,7 @@ from frappe.utils import cint
@frappe.whitelist(allow_guest=True)
def web_search(query, scope=None, limit=20):
def web_search(query: str, scope: str | None = None, limit: int = 20):
from frappe.search.website_search import WebsiteSearch
limit = cint(limit)

View file

@ -543,7 +543,7 @@ def _get_tables(doctypes: list[str], existing_tables: list[str]) -> list[str]:
@frappe.whitelist()
def fetch_latest_backups(partial=False) -> dict:
def fetch_latest_backups(partial: bool = False) -> dict:
"""Fetch paths of the latest backup taken in the last 30 days.
Note: Only for System Managers

View file

@ -8,7 +8,7 @@ from frappe import _
@frappe.whitelist()
def download_pdf(doctype, name, print_format, letterhead=None):
def download_pdf(doctype: str, name: str | int, print_format: str, letterhead: str | None = None):
doc = frappe.get_doc(doctype, name)
doc.check_permission("print")
generator = PrintFormatGenerator(print_format, doc, letterhead)

View file

@ -76,7 +76,7 @@ class DiscussionReply(Document):
@frappe.whitelist()
def delete_message(reply_name):
def delete_message(reply_name: str):
owner = frappe.db.get_value("Discussion Reply", reply_name, "owner")
if owner == frappe.session.user:
frappe.delete_doc("Discussion Reply", reply_name)

View file

@ -23,7 +23,14 @@ class DiscussionTopic(Document):
@frappe.whitelist()
def submit_discussion(doctype, docname, reply, title, topic_name=None, reply_name=None):
def submit_discussion(
doctype: str,
docname: str | int,
reply: str,
title: str,
topic_name: str | None = None,
reply_name: str | None = None,
):
if reply_name:
doc = frappe.get_doc("Discussion Reply", reply_name)
doc.reply = reply

View file

@ -382,7 +382,7 @@ def remove_unverified_record():
@frappe.whitelist(allow_guest=True)
def confirm_deletion(email, name, host_name):
def confirm_deletion(email: str, name: str, host_name: str):
if not verify_request():
return

View file

@ -12,7 +12,7 @@ from frappe.integrations.google_oauth import GoogleOAuth
@frappe.whitelist(methods=["POST"])
def authorize_access(reauthorize=False, code=None):
def authorize_access(reauthorize: bool = False, code: str | None = None):
"""If no Authorization code get it from Google and then request for Refresh Token."""
oauth_code = (

View file

@ -30,7 +30,7 @@ def get_context(context):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=1000, seconds=60 * 60)
def send_message(sender, message, subject="Website Query"):
def send_message(sender: str, message: str, subject: str = "Website Query"):
doc = frappe.get_doc("Contact Us Settings", "Contact Us Settings")
if doc.is_disabled:
return