diff --git a/frappe/__init__.py b/frappe/__init__.py index a5cce1d003..4a2c668355 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -146,6 +146,7 @@ def init(site, sites_path=None, new_site=False): local.role_permissions = {} local.valid_columns = {} local.new_doc_templates = {} + local.link_count = {} local.jenv = None local.jloader =None diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index cfe6d83cbe..550073f663 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -305,26 +305,18 @@ def console(context): def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False, junit_xml_output=False): "Run tests" import frappe.test_runner - from frappe.utils import sel tests = test site = get_site(context) frappe.init(site=site) - if frappe.conf.run_selenium_tests and False: - sel.start(context.verbose, driver) + ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests, + force=context.force, profile=profile, junit_xml_output=junit_xml_output) + if len(ret.failures) == 0 and len(ret.errors) == 0: + ret = 0 - try: - ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests, - force=context.force, profile=profile, junit_xml_output=junit_xml_output) - if len(ret.failures) == 0 and len(ret.errors) == 0: - ret = 0 - finally: - pass - if frappe.conf.run_selenium_tests: - sel.close() - - sys.exit(ret) + if os.environ.get('CI'): + sys.exit(ret) @click.command('run-ui-tests') @click.option('--app', help="App to run tests on, leave blank for all apps") diff --git a/frappe/database.py b/frappe/database.py index 6868710e99..80cdc19d22 100644 --- a/frappe/database.py +++ b/frappe/database.py @@ -20,6 +20,7 @@ from frappe.utils import now, get_datetime, cstr from frappe import _ from types import StringType, UnicodeType from frappe.utils.global_search import sync_global_search +from frappe.model.utils.link_count import flush_local_link_count from six import iteritems @@ -726,7 +727,10 @@ class Database: self.sql("commit") frappe.local.rollback_observers = [] self.flush_realtime_log() + self.enqueue_global_search() + flush_local_link_count() + def enqueue_global_search(self): if frappe.flags.update_global_search: try: frappe.enqueue('frappe.utils.global_search.sync_global_search', diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index bc087f7747..a9d1d6a51a 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -432,7 +432,7 @@ class BaseDocument(object): missing = [] - for df in self.meta.get("fields", {"reqd": 1}): + for df in self.meta.get("fields", {"reqd": ('=', 1)}): if self.get(df.fieldname) in (None, []) or not strip_html(cstr(self.get(df.fieldname))).strip(): missing.append((df.fieldname, get_msg(df))) @@ -456,7 +456,7 @@ class BaseDocument(object): cancelled_links = [] for df in (self.meta.get_link_fields() - + self.meta.get("fields", {"fieldtype":"Dynamic Link"})): + + self.meta.get("fields", {"fieldtype": ('=', "Dynamic Link")})): docname = self.get(df.fieldname) if docname: @@ -543,7 +543,7 @@ class BaseDocument(object): if frappe.flags.in_import or self.is_new() or self.flags.ignore_validate_constants: return - constants = [d.fieldname for d in self.meta.get("fields", {"set_only_once": 1})] + constants = [d.fieldname for d in self.meta.get("fields", {"set_only_once": ('=',1)})] if constants: values = frappe.db.get_value(self.doctype, self.name, constants, as_dict=True) @@ -649,7 +649,7 @@ class BaseDocument(object): if self.flags.ignore_save_passwords: return - for df in self.meta.get('fields', {'fieldtype': 'Password'}): + for df in self.meta.get('fields', {'fieldtype': ('=', 'Password')}): new_password = self.get(df.fieldname) if new_password and not self.is_dummy_password(new_password): # is not a dummy password like '*****' @@ -811,7 +811,7 @@ class BaseDocument(object): def _extract_images_from_text_editor(self): from frappe.utils.file_manager import extract_images_from_doc if self.doctype != "DocType": - for df in self.meta.get("fields", {"fieldtype":"Text Editor"}): + for df in self.meta.get("fields", {"fieldtype": ('=', "Text Editor")}): extract_images_from_doc(self, df.fieldname) def _filter(data, filters, limit=None): @@ -820,23 +820,28 @@ def _filter(data, filters, limit=None): "key": ["in", "val"], "key": ["not in", "val"], "key": "^val", "key" : True (exists), "key": False (does not exist) }""" - out = [] + out, _filters = [], {} - for d in data: - add = True + # setup filters as tuples + if filters: for f in filters: fval = filters[f] - if fval is True: - fval = ("not None", fval) - elif fval is False: - fval = ("None", fval) - elif not isinstance(fval, (tuple, list)): - if isinstance(fval, basestring) and fval.startswith("^"): + if not isinstance(fval, (tuple, list)): + if fval is True: + fval = ("not None", fval) + elif fval is False: + fval = ("None", fval) + elif isinstance(fval, basestring) and fval.startswith("^"): fval = ("^", fval[1:]) else: fval = ("=", fval) + _filters[f] = fval + + for d in data: + add = True + for f, fval in iteritems(_filters): if not frappe.compare(getattr(d, f, None), fval[0], fval[1]): add = False break diff --git a/frappe/model/meta.py b/frappe/model/meta.py index e64286cb9d..78977f18f8 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -29,7 +29,8 @@ from frappe import _ def get_meta(doctype, cached=True): if cached: if not frappe.local.meta_cache.get(doctype): - frappe.local.meta_cache[doctype] = frappe.cache().hget("meta", doctype, lambda: Meta(doctype)) + frappe.local.meta_cache[doctype] = frappe.cache().hget("meta", doctype, + lambda: Meta(doctype)) return frappe.local.meta_cache[doctype] else: return Meta(doctype) diff --git a/frappe/model/utils/link_count.py b/frappe/model/utils/link_count.py index 01af04dc60..98004ef744 100644 --- a/frappe/model/utils/link_count.py +++ b/frappe/model/utils/link_count.py @@ -11,14 +11,26 @@ ignore_doctypes = ("DocType", "Print Format", "Role", "Module Def", "Communicati def notify_link_count(doctype, name): '''updates link count for given document''' + if hasattr(frappe.local, 'link_count'): + if (doctype, name) in frappe.local.link_count: + frappe.local.link_count[(doctype, name)] += 1 + else: + frappe.local.link_count[(doctype, name)] = 1 + +def flush_local_link_count(): + '''flush from local before ending request''' + if not getattr(frappe.local, 'link_count', None): + return + link_count = frappe.cache().get_value('_link_count') if not link_count: link_count = {} - if not (doctype, name) in link_count: - link_count[(doctype, name)] = 1 - else: - link_count[(doctype, name)] += 1 + for key, value in frappe.local.link_count.items(): + if key in link_count: + link_count[key] += frappe.local.link_count[key] + else: + link_count[key] = frappe.local.link_count[key] frappe.cache().set_value('_link_count', link_count) diff --git a/frappe/public/js/frappe/form/script_manager.js b/frappe/public/js/frappe/form/script_manager.js index 1591f0a3bb..ad34dcc6a7 100644 --- a/frappe/public/js/frappe/form/script_manager.js +++ b/frappe/public/js/frappe/form/script_manager.js @@ -73,6 +73,8 @@ frappe.ui.form.ScriptManager = Class.extend({ var handlers = this.get_handlers(event_name, doctype, name, callback); if(callback) handlers.push(callback); + this.frm.selected_doc = frappe.get_doc(doctype, name); + return $.when.apply($, $.map(handlers, function(fn) { return fn(); })); }, get_handlers: function(event_name, doctype, name, callback) { @@ -187,11 +189,16 @@ frappe.ui.form.ScriptManager = Class.extend({ } }, copy_from_first_row: function(parentfield, current_row, fieldnames) { - var doclist = this.frm.doc[parentfield]; - if(doclist.length===1 || doclist[0]===current_row) return; + var data = this.frm.doc[parentfield]; + if(data.length===1 || data[0]===current_row) return; + + if(typeof fieldnames==='string') { + fieldnames = [fieldnames]; + } $.each(fieldnames, function(i, fieldname) { - current_row[fieldname] = doclist[0][fieldname]; + frappe.model.set_value(current_row.doctype, current_row.name, fieldname, + data[0][fieldname]); }); } });