From 63170989f9bea510e7fc1561e84371fccf962180 Mon Sep 17 00:00:00 2001 From: FINE FILM Ltd Date: Mon, 16 Apr 2018 07:14:38 +0200 Subject: [PATCH 01/11] [fix][minor] Fix logical error in event repeat condition check (#5439) Without this fix you can only create Every Day repeating events that are not ending on the same day. The condition is doing the total opposite check, if you are trying to create a repeating event with the same day end you get the following error: "Every day events should finish on the same day." --- frappe/desk/doctype/event/event.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/doctype/event/event.py b/frappe/desk/doctype/event/event.py index 0e97d78fb7..b99b0453f6 100644 --- a/frappe/desk/doctype/event/event.py +++ b/frappe/desk/doctype/event/event.py @@ -27,7 +27,7 @@ class Event(Document): # this scenario doesn't make sense i.e. it starts and ends at the same second! self.ends_on = None - if getdate(self.starts_on) == getdate(self.ends_on) and self.repeat_on == "Every Day": + if getdate(self.starts_on) != getdate(self.ends_on) and self.repeat_on == "Every Day": frappe.msgprint(frappe._("Every day events should finish on the same day."), raise_exception=True) def get_permission_query_conditions(user): From 68377501fcff47eaa02aec2a111b57670f5a8612 Mon Sep 17 00:00:00 2001 From: Manas Solanki Date: Mon, 16 Apr 2018 10:45:02 +0530 Subject: [PATCH 02/11] increase the field limit for the csv file (#5438) --- frappe/core/doctype/data_import/exporter.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/data_import/exporter.py b/frappe/core/doctype/data_import/exporter.py index 9a8ca42b24..2a267c122f 100644 --- a/frappe/core/doctype/data_import/exporter.py +++ b/frappe/core/doctype/data_import/exporter.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe, json from frappe import _ import frappe.permissions -import re, csv, os +import re, csv, os, sys from frappe.utils.csvutils import UnicodeWriter from frappe.utils import cstr, formatdate, format_datetime from frappe.core.doctype.data_import.importer import get_data_keys @@ -289,6 +289,10 @@ def get_template(doctype=None, parent_doctype=None, all_doctypes="No", with_data with open(filename, 'wb') as f: f.write(cstr(w.getvalue()).encode("utf-8")) f = open(filename) + + # increase the field limit in case of larger fields + # works for Python 2.x and 3.x + csv.field_size_limit(sys.maxsize) reader = csv.reader(f) from frappe.utils.xlsxutils import make_xlsx From 74046de5dd71f2925460341529a0afa831f217a5 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 16 Apr 2018 10:57:33 +0530 Subject: [PATCH 03/11] [minor] --- frappe/core/doctype/deleted_document/deleted_document.py | 4 ++-- frappe/model/delete_doc.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/deleted_document/deleted_document.py b/frappe/core/doctype/deleted_document/deleted_document.py index 7dbd4d2645..04ec2e015e 100644 --- a/frappe/core/doctype/deleted_document/deleted_document.py +++ b/frappe/core/doctype/deleted_document/deleted_document.py @@ -18,8 +18,8 @@ def restore(name): doc.insert() except frappe.DocstatusTransitionError: frappe.msgprint(_("Cancelled Document restored as Draft")) - doc.docstatus = 0 - doc.insert() + doc.docstatus = 0 + doc.insert() doc.add_comment('Edit', _('restored {0} as {1}').format(deleted.deleted_name, doc.name)) diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index 979bcc1885..ac112ddaf3 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -133,7 +133,7 @@ def delete_from_table(doctype, name, ignore_doctypes, doc): if doctype!="DocType" and doctype==name: frappe.db.sql("delete from `tabSingles` where doctype=%s", name) else: - frappe.db.sql("delete from `tab%s` where name=%s" % (frappe.db.escape(doctype), "%s"), (name,)) + frappe.db.sql("delete from `tab{0}` where name=%s".format(doctype), name) # get child tables if doc: From 102dd9fea82584330563e017a4b26bfba8b0460c Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 16 Apr 2018 11:04:07 +0530 Subject: [PATCH 04/11] [travis] sleep more --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc89895bab..1d82080570 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ install: - sudo apt-get purge -y mysql-common mysql-server mysql-client - nvm install v7.10.0 - wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py - + - sudo python install.py --develop --user travis --without-bench-setup - sudo pip install -e ~/bench @@ -34,7 +34,7 @@ before_script: - bench setup-help - bench scheduler disable - bench start & - - sleep 10 + - sleep 20 script: - set -e From e4aa433ea346f60cb0a09d148e1a904afd176494 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 16 Apr 2018 11:25:39 +0530 Subject: [PATCH 05/11] [travis] --quiet --- .travis.yml | 2 +- frappe/commands/scheduler.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d82080570..f58e15cb31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ before_script: - bench setup-help - bench scheduler disable - bench start & - - sleep 20 + - sleep 10 script: - set -e diff --git a/frappe/commands/scheduler.py b/frappe/commands/scheduler.py index e03a9b6078..caa0d7ed62 100755 --- a/frappe/commands/scheduler.py +++ b/frappe/commands/scheduler.py @@ -152,9 +152,10 @@ def start_scheduler(): @click.command('worker') @click.option('--queue', type=str) -def start_worker(queue): +@click.option('--quiet', is_flag = True, default = False, help = 'Hide Log Outputs') +def start_worker(queue, quiet = False): from frappe.utils.background_jobs import start_worker - start_worker(queue) + start_worker(queue, quiet = quiet) @click.command('ready-for-migration') @click.option('--site', help='site name') From 64fe2749cb33f776ae9047ee2d29b660477ba566 Mon Sep 17 00:00:00 2001 From: Shreya Shah Date: Mon, 16 Apr 2018 14:55:34 +0530 Subject: [PATCH 06/11] avoid link validation error in authentication (#5415) --- frappe/core/doctype/activity_log/activity_log.py | 2 +- frappe/model/document.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/activity_log/activity_log.py b/frappe/core/doctype/activity_log/activity_log.py index 33e444650b..94a4803279 100644 --- a/frappe/core/doctype/activity_log/activity_log.py +++ b/frappe/core/doctype/activity_log/activity_log.py @@ -41,7 +41,7 @@ def add_authentication_log(subject, user, operation="Login", status="Success"): "status": status, "subject": subject, "operation": operation, - }).insert(ignore_permissions=True) + }).insert(ignore_permissions=True, ignore_links=True) def clear_authentication_logs(): """clear 100 day old authentication logs""" diff --git a/frappe/model/document.py b/frappe/model/document.py index 02c77a2884..0e232fc006 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -184,7 +184,7 @@ class Document(BaseDocument): frappe.flags.error_message = _('Insufficient Permission for {0}').format(self.doctype) raise frappe.PermissionError - def insert(self, ignore_permissions=None, ignore_if_duplicate=False, ignore_mandatory=None): + def insert(self, ignore_permissions=None, ignore_links=None, ignore_if_duplicate=False, ignore_mandatory=None): """Insert the document in the database (as a new document). This will check for user permissions and execute `before_insert`, `validate`, `on_update`, `after_insert` methods if they are written. @@ -198,6 +198,9 @@ class Document(BaseDocument): if ignore_permissions!=None: self.flags.ignore_permissions = ignore_permissions + if ignore_links!=None: + self.flags.ignore_links = ignore_links + if ignore_mandatory!=None: self.flags.ignore_mandatory = ignore_mandatory From fc7de01017175ea9cee1452caceffc5de1662263 Mon Sep 17 00:00:00 2001 From: Shreya Shah Date: Mon, 16 Apr 2018 14:56:19 +0530 Subject: [PATCH 07/11] Raise exception while deleting an item which is a product bundle (#5286) * raise exception while deleting an item which is a product bundle * separated if statements and added a comment * modified condition --- frappe/model/delete_doc.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index ac112ddaf3..b452073467 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -193,13 +193,20 @@ def check_if_doc_is_linked(doc, method="Delete"): # don't check for communication and todo! continue - if item and ((item.parent or item.name) != doc.name) \ - and ((method=="Delete" and item.docstatus<2) or (method=="Cancel" and item.docstatus==1)): - # raise exception only if - # linked to an non-cancelled doc when deleting - # or linked to a submitted doc when cancelling + if not item: + continue + elif (method != "Delete" or item.docstatus == 2) and (method != "Cancel" or item.docstatus != 1): + # don't raise exception if not + # linked to a non-cancelled doc when deleting or to a submitted doc when cancelling + continue + elif link_dt == doc.doctype and (item.parent or item.name) == doc.name: + # don't raise exception if not + # linked to same item or doc having same name as the item + continue + else: reference_docname = item.parent or item.name raise_link_exists_exception(doc, linked_doctype, reference_docname) + else: if frappe.db.get_value(link_dt, None, link_field) == doc.name: raise_link_exists_exception(doc, link_dt, link_dt) From f03ac687ab6c89ff1f833d184d42d94448a0f966 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 16 Apr 2018 15:08:23 +0530 Subject: [PATCH 08/11] [travis] --quiet --- frappe/utils/background_jobs.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index ef236b45af..4ed70fa2d0 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -127,7 +127,7 @@ def execute_job(site, method, event, job_name, kwargs, user=None, async=True, re if async: frappe.destroy() -def start_worker(queue=None): +def start_worker(queue=None, quiet = False): '''Wrapper to start rq worker. Connects to redis and monitors these queues.''' with frappe.init_site(): # empty init is required to get redis_queue from common_site_config.json @@ -138,7 +138,10 @@ def start_worker(queue=None): with Connection(redis_connection): queues = get_queue_list(queue) - Worker(queues, name=get_worker_name(queue)).work() + logging_level = "INFO" + if quiet: + logging_level = "WARNING" + Worker(queues, name=get_worker_name(queue)).work(logging_level = logging_level) def get_worker_name(queue): '''When limiting worker to a specific queue, also append queue name to default worker name''' From c007c0c22591931d2ff0d01d1974f92cb2cbd32a Mon Sep 17 00:00:00 2001 From: Shreya Shah Date: Tue, 17 Apr 2018 11:29:22 +0530 Subject: [PATCH 09/11] Fix for unknown locale languages in print format (#5424) * fix for unknown locale in dates * formatting fix --- frappe/utils/data.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 03214df80e..d6618d3b07 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -26,9 +26,9 @@ def getdate(string_date=None): """ Coverts string date (yyyy-mm-dd) to datetime.date object """ + if not string_date: return get_datetime().date() - if isinstance(string_date, datetime.datetime): return string_date.date() @@ -38,7 +38,6 @@ def getdate(string_date=None): # dateutil parser does not agree with dates like 0000-00-00 if not string_date or string_date=="0000-00-00": return None - return parser.parse(string_date).date() def get_datetime(datetime_str=None): @@ -199,7 +198,6 @@ def get_time(time_str): def get_datetime_str(datetime_obj): if isinstance(datetime_obj, string_types): datetime_obj = get_datetime(datetime_obj) - return datetime_obj.strftime(DATETIME_FORMAT) def get_user_format(): @@ -226,11 +224,11 @@ def formatdate(string_date=None, format_string=None): date = getdate(string_date) if not format_string: format_string = get_user_format().replace("mm", "MM") - try: formatted_date = babel.dates.format_date(date, format_string, locale=(frappe.local.lang or "").replace("-", "_")) except UnknownLocaleError: - formatted_date = date.strftime("%Y-%m-%d") + format_string = format_string.replace("MM", "%m").replace("dd", "%d").replace("yyyy", "%Y") + formatted_date = date.strftime(format_string) return formatted_date def format_time(txt): From de63fa5737ec7db123591912e59a12de9e16ecd4 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 17 Apr 2018 11:58:01 +0530 Subject: [PATCH 10/11] Sync optimization related to varchar length and index on version table (#5437) * Sync optimization related to varchar length and index on version table * Minor fix --- frappe/core/doctype/version/version.json | 2 +- frappe/core/doctype/version/version.py | 5 ++- frappe/model/db_schema.py | 54 +++++++++++++----------- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/frappe/core/doctype/version/version.json b/frappe/core/doctype/version/version.json index 37294355ee..57cd54b6d2 100644 --- a/frappe/core/doctype/version/version.json +++ b/frappe/core/doctype/version/version.json @@ -188,7 +188,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-12-29 14:39:45.926836", + "modified": "2018-04-10 14:39:45.926836", "modified_by": "Administrator", "module": "Core", "name": "Version", diff --git a/frappe/core/doctype/version/version.py b/frappe/core/doctype/version/version.py index 671eb8c597..9d945fed11 100644 --- a/frappe/core/doctype/version/version.py +++ b/frappe/core/doctype/version/version.py @@ -85,4 +85,7 @@ def get_diff(old, new, for_child=False): return out else: - return None \ No newline at end of file + return None + +def on_doctype_update(): + frappe.db.add_index("Version", ["ref_doctype", "docname"]) \ No newline at end of file diff --git a/frappe/model/db_schema.py b/frappe/model/db_schema.py index 64d7daca71..a52538eb1d 100644 --- a/frappe/model/db_schema.py +++ b/frappe/model/db_schema.py @@ -110,7 +110,8 @@ class DbTable: for col in columns: if len(col.fieldname) >= 64: - frappe.throw(_("Fieldname is limited to 64 characters ({0})").format(frappe.bold(col.fieldname))) + frappe.throw(_("Fieldname is limited to 64 characters ({0})") + .format(frappe.bold(col.fieldname))) if col.fieldtype in type_map and type_map[col.fieldtype][0]=="varchar": @@ -119,33 +120,35 @@ class DbTable: if not (1 <= new_length <= 1000): frappe.throw(_("Length of {0} should be between 1 and 1000").format(col.fieldname)) - try: - # check for truncation - max_length = frappe.db.sql("""select max(char_length(`{fieldname}`)) from `tab{doctype}`"""\ - .format(fieldname=col.fieldname, doctype=self.doctype)) + current_col = self.current_columns.get(col.fieldname, {}) + if not current_col: + continue + current_type = self.current_columns[col.fieldname]["type"] + current_length = re.findall('varchar\(([\d]+)\)', current_type) + if not current_length: + # case when the field is no longer a varchar + continue + current_length = current_length[0] + if cint(current_length) != cint(new_length): + try: + # check for truncation + max_length = frappe.db.sql("""select max(char_length(`{fieldname}`)) from `tab{doctype}`"""\ + .format(fieldname=col.fieldname, doctype=self.doctype)) - except pymysql.InternalError as e: - if e.args[0] == ER.BAD_FIELD_ERROR: - # Unknown column 'column_name' in 'field list' - continue + except pymysql.InternalError as e: + if e.args[0] == ER.BAD_FIELD_ERROR: + # Unknown column 'column_name' in 'field list' + continue - else: - raise + else: + raise - if max_length and max_length[0][0] and max_length[0][0] > new_length: - current_type = self.current_columns[col.fieldname]["type"] - current_length = re.findall('varchar\(([\d]+)\)', current_type) - if not current_length: - # case when the field is no longer a varchar - continue + if max_length and max_length[0][0] and max_length[0][0] > new_length: + if col.fieldname in self.columns: + self.columns[col.fieldname].length = current_length - current_length = current_length[0] - - if col.fieldname in self.columns: - self.columns[col.fieldname].length = current_length - - frappe.msgprint(_("Reverting length to {0} for '{1}' in '{2}'; Setting the length as {3} will cause truncation of data.")\ - .format(current_length, col.fieldname, self.doctype, new_length)) + frappe.msgprint(_("Reverting length to {0} for '{1}' in '{2}'; Setting the length as {3} will cause truncation of data.")\ + .format(current_length, col.fieldname, self.doctype, new_length)) def sync(self): @@ -180,7 +183,8 @@ class DbTable: parentfield varchar({varchar_len}), parenttype varchar({varchar_len}), idx int(8) not null default '0', - %sindex parent(parent)) + %sindex parent(parent), + index modified(modified)) ENGINE={engine} ROW_FORMAT=COMPRESSED CHARACTER SET=utf8mb4 From 0a18c47fda059a9b185bab5b8c45607e2aa59b38 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 19 Apr 2018 11:30:11 +0600 Subject: [PATCH 11/11] bumped to version 10.1.24 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a4d1aef275..264d93a80d 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json from .exceptions import * from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template -__version__ = '10.1.23' +__version__ = '10.1.24' __title__ = "Frappe Framework" local = Local()