Merge branch 'develop' into fix-frappe-qb-set-syntax-in-email-account
This commit is contained in:
commit
7c6b3dbc80
17 changed files with 207 additions and 72 deletions
|
|
@ -92,15 +92,15 @@ context('Control Date, Time and DateTime', () => {
|
|||
date_format: 'dd.mm.yyyy',
|
||||
time_format: 'HH:mm:ss',
|
||||
value: ' 02.12.2019 11:00:12',
|
||||
doc_value: '2019-12-02 11:00:12',
|
||||
input_value: '02.12.2019 11:00:12'
|
||||
doc_value: '2019-12-02 00:30:12', // system timezone (America/New_York)
|
||||
input_value: '02.12.2019 11:00:12' // admin timezone (Asia/Kolkata)
|
||||
},
|
||||
{
|
||||
date_format: 'mm-dd-yyyy',
|
||||
time_format: 'HH:mm',
|
||||
value: ' 12-02-2019 11:00:00',
|
||||
doc_value: '2019-12-02 11:00:00',
|
||||
input_value: '12-02-2019 11:00'
|
||||
doc_value: '2019-12-02 00:30:00', // system timezone (America/New_York)
|
||||
input_value: '12-02-2019 11:00' // admin timezone (Asia/Kolkata)
|
||||
}
|
||||
];
|
||||
datetime_formats.forEach(d => {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_p
|
|||
from frappe.model.base_document import get_controller
|
||||
from frappe.social.doctype.post.post import frequently_visited_links
|
||||
from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings, get_app_logo
|
||||
from frappe.utils import get_time_zone
|
||||
|
||||
def get_bootinfo():
|
||||
"""build and return boot info"""
|
||||
|
|
@ -58,6 +59,7 @@ def get_bootinfo():
|
|||
bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1})
|
||||
bootinfo.navbar_settings = get_navbar_settings()
|
||||
bootinfo.notification_settings = get_notification_settings()
|
||||
set_time_zone(bootinfo)
|
||||
|
||||
# ipinfo
|
||||
if frappe.session.data.get('ipinfo'):
|
||||
|
|
@ -220,8 +222,8 @@ def load_translations(bootinfo):
|
|||
bootinfo["__messages"] = messages
|
||||
|
||||
def get_user_info():
|
||||
user_info = frappe.db.get_all('User', fields=['`name`', 'full_name as fullname', 'user_image as image',
|
||||
'gender', 'email', 'username', 'bio', 'location', 'interest', 'banner_image', 'allowed_in_mentions', 'user_type'],
|
||||
user_info = frappe.db.get_all('User', fields=['`name`', 'full_name as fullname', 'user_image as image', 'gender',
|
||||
'email', 'username', 'bio', 'location', 'interest', 'banner_image', 'allowed_in_mentions', 'user_type', 'time_zone'],
|
||||
filters=dict(enabled=1))
|
||||
|
||||
user_info_map = {d.name: d for d in user_info}
|
||||
|
|
@ -324,3 +326,9 @@ def get_desk_settings():
|
|||
|
||||
def get_notification_settings():
|
||||
return frappe.get_cached_doc('Notification Settings', frappe.session.user)
|
||||
|
||||
def set_time_zone(bootinfo):
|
||||
bootinfo.time_zone = {
|
||||
"system": get_time_zone(),
|
||||
"user": bootinfo.get("user_info", {}).get(frappe.session.user, {}).get("time_zone", None) or get_time_zone()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,19 @@ def run_server_script_for_doc_event(doc, event):
|
|||
if scripts:
|
||||
# run all scripts for this doctype + event
|
||||
for script_name in scripts:
|
||||
frappe.get_doc('Server Script', script_name).execute_doc(doc)
|
||||
try:
|
||||
frappe.get_doc('Server Script', script_name).execute_doc(doc)
|
||||
except Exception as e:
|
||||
message = frappe._('Error executing Server Script {0}. Open Browser Console to see traceback.').format(
|
||||
frappe.utils.get_link_to_form('Server Script', script_name)
|
||||
)
|
||||
exception = type(e)
|
||||
if getattr(frappe, 'request', None):
|
||||
# all exceptions throw 500 which is internal server error
|
||||
# however server script error is a user error
|
||||
# so we should throw 417 which is expectation failed
|
||||
exception.http_status_code = 417
|
||||
frappe.throw(title=frappe._('Server Script Error'), msg=message, exc=exception)
|
||||
|
||||
def get_server_script_map():
|
||||
# fetch cached server script methods
|
||||
|
|
|
|||
|
|
@ -32,5 +32,11 @@ frappe.ui.form.on("System Settings", {
|
|||
frm.set_value('prepared_report_expiry_period', 7);
|
||||
}
|
||||
}
|
||||
},
|
||||
on_update: function(frm) {
|
||||
if (frappe.boot.time_zone && frappe.boot.time_zone.system !== frm.doc.time_zone) {
|
||||
// Clear cache after saving to refresh the values of boot.
|
||||
frappe.ui.toolbar.clear_cache();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@
|
|||
"fieldname": "time_zone",
|
||||
"fieldtype": "Select",
|
||||
"label": "Time Zone",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -77,7 +77,12 @@ frappe.ui.form.on('User', {
|
|||
}
|
||||
},
|
||||
refresh: function(frm) {
|
||||
var doc = frm.doc;
|
||||
let doc = frm.doc;
|
||||
|
||||
if (frm.is_new()) {
|
||||
frm.set_value("time_zone", frappe.sys_defaults.time_zone);
|
||||
}
|
||||
|
||||
if (in_list(['System User', 'Website User'], frm.doc.user_type)
|
||||
&& !frm.is_new() && !frm.roles_editor && frm.can_edit_roles) {
|
||||
frm.reload_doc();
|
||||
|
|
@ -267,6 +272,12 @@ frappe.ui.form.on('User', {
|
|||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
on_update: function(frm) {
|
||||
if (frappe.boot.time_zone && frappe.boot.time_zone.user !== frm.doc.time_zone) {
|
||||
// Clear cache after saving to refresh the values of boot.
|
||||
frappe.ui.toolbar.clear_cache();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import frappe.defaults
|
|||
import frappe.permissions
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import (cint, flt, has_gravatar, escape_html, format_datetime,
|
||||
now_datetime, get_formatted_email, today)
|
||||
now_datetime, get_formatted_email, today, get_time_zone)
|
||||
from frappe import throw, msgprint, _
|
||||
from frappe.utils.password import update_password as _update_password, check_password, get_password_reset_limit
|
||||
from frappe.desk.notifications import clear_notifications
|
||||
|
|
@ -74,6 +74,7 @@ class User(Document):
|
|||
self.validate_roles()
|
||||
self.validate_allowed_modules()
|
||||
self.validate_user_image()
|
||||
self.set_time_zone()
|
||||
|
||||
if self.language == "Loading...":
|
||||
self.language = None
|
||||
|
|
@ -227,11 +228,11 @@ class User(Document):
|
|||
def validate_share(self, docshare):
|
||||
pass
|
||||
# if docshare.user == self.name:
|
||||
# if self.user_type=="System User":
|
||||
# if docshare.share != 1:
|
||||
# frappe.throw(_("Sorry! User should have complete access to their own record."))
|
||||
# else:
|
||||
# frappe.throw(_("Sorry! Sharing with Website User is prohibited."))
|
||||
# if self.user_type=="System User":
|
||||
# if docshare.share != 1:
|
||||
# frappe.throw(_("Sorry! User should have complete access to their own record."))
|
||||
# else:
|
||||
# frappe.throw(_("Sorry! Sharing with Website User is prohibited."))
|
||||
|
||||
def send_password_notification(self, new_password):
|
||||
try:
|
||||
|
|
@ -596,6 +597,10 @@ class User(Document):
|
|||
|
||||
return user
|
||||
|
||||
def set_time_zone(self):
|
||||
if not self.time_zone:
|
||||
self.time_zone = get_time_zone()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_timezones():
|
||||
import pytz
|
||||
|
|
|
|||
|
|
@ -120,6 +120,11 @@ class Meta(Document):
|
|||
or (not no_nulls and value is None)):
|
||||
out[key] = value
|
||||
|
||||
# set empty lists for unset table fields
|
||||
for table_field in DOCTYPE_TABLE_FIELDS:
|
||||
if not out.get(table_field.fieldname):
|
||||
out[table_field.fieldname] = []
|
||||
|
||||
return out
|
||||
|
||||
return serialize(self)
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat
|
|||
let date_format = sysdefaults && sysdefaults.date_format
|
||||
? sysdefaults.date_format : 'yyyy-mm-dd';
|
||||
|
||||
let now_date = new Date();
|
||||
|
||||
this.today_text = __("Today");
|
||||
this.date_format = frappe.defaultDateFormat;
|
||||
this.datepicker_options = {
|
||||
|
|
@ -62,7 +60,7 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat
|
|||
autoClose: true,
|
||||
todayButton: true,
|
||||
dateFormat: date_format,
|
||||
startDate: now_date,
|
||||
startDate: this.get_start_date(),
|
||||
keyboardNav: false,
|
||||
onSelect: () => {
|
||||
this.$input.trigger('change');
|
||||
|
|
@ -77,6 +75,11 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat
|
|||
...(this.get_df_options())
|
||||
};
|
||||
}
|
||||
|
||||
get_start_date() {
|
||||
return new Date(this.get_now_date());
|
||||
}
|
||||
|
||||
set_datepicker() {
|
||||
this.$input.datepicker(this.datepicker_options);
|
||||
this.datepicker = this.$input.data('datepicker');
|
||||
|
|
@ -113,7 +116,7 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat
|
|||
this.datepicker.update('position', position);
|
||||
}
|
||||
get_now_date() {
|
||||
return frappe.datetime.now_date(true);
|
||||
return frappe.datetime.convert_to_system_tz(frappe.datetime.now_date(true));
|
||||
}
|
||||
set_t_for_today() {
|
||||
var me = this;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,22 @@
|
|||
frappe.ui.form.ControlDatetime = class ControlDatetime extends frappe.ui.form.ControlDate {
|
||||
set_formatted_input(value) {
|
||||
if (this.timepicker_only) return;
|
||||
if (!this.datepicker) return;
|
||||
if (!value) {
|
||||
this.datepicker.clear();
|
||||
return;
|
||||
} else if (value === "Today") {
|
||||
value = this.get_now_date();
|
||||
}
|
||||
value = this.format_for_input(value);
|
||||
this.$input && this.$input.val(value);
|
||||
this.datepicker.selectDate(frappe.datetime.user_to_obj(value));
|
||||
}
|
||||
|
||||
get_start_date() {
|
||||
let value = frappe.datetime.convert_to_user_tz(this.value);
|
||||
return frappe.datetime.str_to_obj(value);
|
||||
}
|
||||
set_date_options() {
|
||||
super.set_date_options();
|
||||
this.today_text = __("Now");
|
||||
|
|
@ -14,10 +32,31 @@ frappe.ui.form.ControlDatetime = class ControlDatetime extends frappe.ui.form.Co
|
|||
get_now_date() {
|
||||
return frappe.datetime.now_datetime(true);
|
||||
}
|
||||
parse(value) {
|
||||
if (value) {
|
||||
value = frappe.datetime.user_to_str(value, false);
|
||||
|
||||
if (!frappe.datetime.is_system_time_zone()) {
|
||||
value = frappe.datetime.convert_to_system_tz(value, true);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
format_for_input(value) {
|
||||
if (!value) return "";
|
||||
|
||||
|
||||
return frappe.datetime.str_to_user(value, false);
|
||||
}
|
||||
set_description() {
|
||||
const { description } = this.df;
|
||||
const { time_zone } = frappe.sys_defaults;
|
||||
if (!this.df.hide_timezone && !frappe.datetime.is_timezone_same()) {
|
||||
const description = this.df.description;
|
||||
const time_zone = this.get_user_time_zone();
|
||||
|
||||
if (!this.df.hide_timezone) {
|
||||
// Always show the timezone when rendering the Datetime field since the datetime value will
|
||||
// always be in system_time_zone rather then local time.
|
||||
|
||||
if (!description) {
|
||||
this.df.description = time_zone;
|
||||
} else if (!description.includes(time_zone)) {
|
||||
|
|
@ -26,6 +65,9 @@ frappe.ui.form.ControlDatetime = class ControlDatetime extends frappe.ui.form.Co
|
|||
}
|
||||
super.set_description();
|
||||
}
|
||||
get_user_time_zone() {
|
||||
return frappe.boot.time_zone ? frappe.boot.time_zone.user : frappe.sys_defaults.time_zone;
|
||||
}
|
||||
set_datepicker() {
|
||||
super.set_datepicker();
|
||||
if (this.datepicker.opts.timeFormat.indexOf('s') == -1) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ frappe.ui.form.ControlTime = class ControlTime extends frappe.ui.form.ControlDat
|
|||
set_description() {
|
||||
const { description } = this.df;
|
||||
const { time_zone } = frappe.sys_defaults;
|
||||
if (!frappe.datetime.is_timezone_same()) {
|
||||
if (!frappe.datetime.is_system_time_zone()) {
|
||||
if (!description) {
|
||||
this.df.description = time_zone;
|
||||
} else if (!description.includes(time_zone)) {
|
||||
|
|
|
|||
|
|
@ -167,12 +167,8 @@ frappe.form.formatters = {
|
|||
},
|
||||
Datetime: function(value) {
|
||||
if(value) {
|
||||
var m = moment(frappe.datetime.convert_to_user_tz(value));
|
||||
if(frappe.boot.sysdefaults.time_zone) {
|
||||
m = m.tz(frappe.boot.sysdefaults.time_zone);
|
||||
}
|
||||
return m.format(frappe.boot.sysdefaults.date_format.toUpperCase()
|
||||
+ ' ' + (frappe.boot.sysdefaults.time_format || 'HH:mm:ss'));
|
||||
return moment(frappe.datetime.convert_to_user_tz(value))
|
||||
.format(frappe.boot.sysdefaults.date_format.toUpperCase() + ' ' + frappe.boot.sysdefaults.time_format || 'HH:mm:ss');
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,33 +13,48 @@ frappe.provide("frappe.datetime");
|
|||
$.extend(frappe.datetime, {
|
||||
convert_to_user_tz: function(date, format) {
|
||||
// format defaults to true
|
||||
if(frappe.sys_defaults.time_zone) {
|
||||
var date_obj = moment.tz(date, frappe.sys_defaults.time_zone).local();
|
||||
// Converts the datetime string to system time zone first since the database only stores datetime in
|
||||
// system time zone and then convert the string to user time zone(from User doctype).
|
||||
let date_obj = null;
|
||||
if (frappe.boot.time_zone && frappe.boot.time_zone.system && frappe.boot.time_zone.user) {
|
||||
date_obj = moment.tz(date, frappe.boot.time_zone.system)
|
||||
.clone()
|
||||
.tz(frappe.boot.time_zone.user);
|
||||
} else {
|
||||
var date_obj = moment(date);
|
||||
date_obj = moment(date);
|
||||
}
|
||||
|
||||
return (format===false) ? date_obj : date_obj.format(frappe.defaultDatetimeFormat);
|
||||
return format === false ? date_obj : date_obj.format(frappe.defaultDatetimeFormat);
|
||||
},
|
||||
|
||||
convert_to_system_tz: function(date, format) {
|
||||
// format defaults to true
|
||||
|
||||
if(frappe.sys_defaults.time_zone) {
|
||||
var date_obj = moment(date).tz(frappe.sys_defaults.time_zone);
|
||||
// Converts the datetime string to user time zone (from User doctype) first since this fn is called in datetime which accepts datetime
|
||||
// in user time zone then convert the string to user time zone.
|
||||
// This is done so that only one timezone is present in database and we do not end up storing local timezone since it changes
|
||||
// as per the location of user.
|
||||
let date_obj = null;
|
||||
if (frappe.boot.time_zone && frappe.boot.time_zone.system && frappe.boot.time_zone.user) {
|
||||
date_obj = moment.tz(date, frappe.boot.time_zone.user)
|
||||
.clone()
|
||||
.tz(frappe.boot.time_zone.system);
|
||||
} else {
|
||||
var date_obj = moment(date);
|
||||
date_obj = moment(date);
|
||||
}
|
||||
|
||||
return (format===false) ? date_obj : date_obj.format(frappe.defaultDatetimeFormat);
|
||||
return format===false ? date_obj : date_obj.format(frappe.defaultDatetimeFormat);
|
||||
},
|
||||
|
||||
is_system_time_zone: function() {
|
||||
if (frappe.boot.time_zone && frappe.boot.time_zone.system && frappe.boot.time_zone.user) {
|
||||
return moment().tz(frappe.boot.time_zone.system).utcOffset() === moment().tz(frappe.boot.time_zone.user).utcOffset();
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
is_timezone_same: function() {
|
||||
if(frappe.sys_defaults.time_zone) {
|
||||
return moment().tz(frappe.sys_defaults.time_zone).utcOffset() === moment().utcOffset();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return frappe.datetime.is_system_time_zone();
|
||||
},
|
||||
|
||||
str_to_obj: function(d) {
|
||||
|
|
@ -98,11 +113,11 @@ $.extend(frappe.datetime, {
|
|||
return moment().endOf("quarter").format();
|
||||
},
|
||||
|
||||
year_start: function(){
|
||||
year_start: function() {
|
||||
return moment().startOf("year").format();
|
||||
},
|
||||
|
||||
year_end: function(){
|
||||
year_end: function() {
|
||||
return moment().endOf("year").format();
|
||||
},
|
||||
|
||||
|
|
@ -119,19 +134,25 @@ $.extend(frappe.datetime, {
|
|||
},
|
||||
|
||||
str_to_user: function(val, only_time = false) {
|
||||
if(!val) return "";
|
||||
if (!val) return "";
|
||||
const user_date_fmt = frappe.datetime.get_user_date_fmt().toUpperCase();
|
||||
const user_time_fmt = frappe.datetime.get_user_time_fmt();
|
||||
let user_format = user_time_fmt;
|
||||
|
||||
var user_time_fmt = frappe.datetime.get_user_time_fmt();
|
||||
if(only_time) {
|
||||
return moment(val, frappe.defaultTimeFormat)
|
||||
.format(user_time_fmt);
|
||||
}
|
||||
|
||||
var user_date_fmt = frappe.datetime.get_user_date_fmt().toUpperCase();
|
||||
if(typeof val !== "string" || val.indexOf(" ")===-1) {
|
||||
return moment(val).format(user_date_fmt);
|
||||
if (only_time) {
|
||||
let date_obj = moment(val, frappe.defaultTimeFormat);
|
||||
return date_obj.format(user_format);
|
||||
} else {
|
||||
return moment(val, "YYYY-MM-DD HH:mm:ss").format(user_date_fmt + " " + user_time_fmt);
|
||||
let date_obj = moment.tz(val, frappe.boot.time_zone.system);
|
||||
if (typeof val !== "string" || val.indexOf(" ") === -1) {
|
||||
user_format = user_date_fmt;
|
||||
} else {
|
||||
user_format = user_date_fmt + " " + user_time_fmt;
|
||||
}
|
||||
return date_obj
|
||||
.clone()
|
||||
.tz(frappe.boot.time_zone.user)
|
||||
.format(user_format);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -186,23 +207,22 @@ $.extend(frappe.datetime, {
|
|||
},
|
||||
|
||||
_date: function(format, as_obj = false) {
|
||||
const time_zone = frappe.sys_defaults && frappe.sys_defaults.time_zone;
|
||||
let date;
|
||||
if (time_zone) {
|
||||
date = moment.tz(time_zone);
|
||||
} else {
|
||||
date = moment();
|
||||
}
|
||||
if (as_obj) {
|
||||
return frappe.datetime.moment_to_date_obj(date);
|
||||
} else {
|
||||
return date.format(format);
|
||||
}
|
||||
/**
|
||||
* Whenever we are getting now_date/datetime, always make sure dates are fetched using user time zone.
|
||||
* This is to make sure that time is as per user time zone set in User doctype, If a user had to change the timezone,
|
||||
* we will end up having multiple timezone by not honouring timezone in User doctype.
|
||||
* This will make sure that at any point we know which timezone the user if following and not have random timezone
|
||||
* when the timezone of the local machine changes.
|
||||
*/
|
||||
let time_zone = frappe.boot.time_zone ? frappe.boot.time_zone.user || frappe.boot.time_zone.system : frappe.sys_defaults.time_zone;
|
||||
let date = moment.tz(time_zone);
|
||||
|
||||
return as_obj ? frappe.datetime.moment_to_date_obj(date) : date.format(format);
|
||||
},
|
||||
|
||||
moment_to_date_obj: function(moment) {
|
||||
moment_to_date_obj: function(moment_obj) {
|
||||
const date_obj = new Date();
|
||||
const date_array = moment.toArray();
|
||||
const date_array = moment_obj.toArray();
|
||||
date_obj.setFullYear(date_array[0]);
|
||||
date_obj.setMonth(date_array[1]);
|
||||
date_obj.setDate(date_array[2]);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ function prettyDate(date, mini) {
|
|||
date = new Date((date || "").replace(/-/g, "/").replace(/[TZ]/g, " ").replace(/\.[0-9]*/, ""));
|
||||
}
|
||||
|
||||
let diff = (((new Date()).getTime() - date.getTime()) / 1000);
|
||||
let diff = (((new Date(frappe.datetime.now_datetime())).getTime() - date.getTime()) / 1000);
|
||||
let day_diff = Math.floor(diff / 86400);
|
||||
|
||||
if (isNaN(day_diff) || day_diff < 0) return '';
|
||||
|
|
|
|||
|
|
@ -882,7 +882,8 @@ number_format_info = {
|
|||
"#,##,###.##": (".", ",", 2),
|
||||
"#,###.###": (".", ",", 3),
|
||||
"#.###": ("", ".", 0),
|
||||
"#,###": ("", ",", 0)
|
||||
"#,###": ("", ",", 0),
|
||||
"#.########": (".", "", 8)
|
||||
}
|
||||
|
||||
def get_number_format_info(format):
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ def strip_exif_data(content, content_type):
|
|||
|
||||
original_image = Image.open(io.BytesIO(content))
|
||||
output = io.BytesIO()
|
||||
# ref: https://stackoverflow.com/a/48248432
|
||||
if content_type == "image/jpeg" and original_image.mode in ("RGBA", "P"):
|
||||
original_image = original_image.convert("RGB")
|
||||
|
||||
new_image = Image.new(original_image.mode, original_image.size)
|
||||
new_image.putdata(list(original_image.getdata()))
|
||||
|
|
|
|||
|
|
@ -184,10 +184,32 @@ def get_safe_globals():
|
|||
# allow iterators and list comprehension
|
||||
out._getiter_ = iter
|
||||
out._iter_unpack_sequence_ = RestrictedPython.Guards.guarded_iter_unpack_sequence
|
||||
out.sorted = sorted
|
||||
|
||||
# add common python builtins
|
||||
out.update(get_python_builtins())
|
||||
|
||||
return out
|
||||
|
||||
def get_python_builtins():
|
||||
return {
|
||||
'abs': abs,
|
||||
'all': all,
|
||||
'any': any,
|
||||
'bool': bool,
|
||||
'dict': dict,
|
||||
'enumerate': enumerate,
|
||||
'isinstance': isinstance,
|
||||
'issubclass': issubclass,
|
||||
'list': list,
|
||||
'max': max,
|
||||
'min': min,
|
||||
'range': range,
|
||||
'set': set,
|
||||
'sorted': sorted,
|
||||
'sum': sum,
|
||||
'tuple': tuple,
|
||||
}
|
||||
|
||||
def get_hooks(hook=None, default=None, app_name=None):
|
||||
hooks = frappe.get_hooks(hook=hook, default=default, app_name=app_name)
|
||||
return copy.deepcopy(hooks)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue