From b51ad328afeb65f6e12d52e607db53ae2f3386e5 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:17:59 +0530 Subject: [PATCH 01/13] Convert dict.keys() to list --- frappe/utils/bench_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/bench_helper.py b/frappe/utils/bench_helper.py index c4bb11d424..795deda05a 100644 --- a/frappe/utils/bench_helper.py +++ b/frappe/utils/bench_helper.py @@ -74,7 +74,7 @@ def get_app_commands(app): @click.command('get-frappe-commands') def get_frappe_commands(): - commands = get_app_commands('frappe').keys() + commands = list(get_app_commands('frappe').keys()) for app in get_apps(): app_commands = get_app_commands(app) From 6f7be6305405c7535f38afd70f002ea631cc7e22 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:26:35 +0530 Subject: [PATCH 02/13] Encode 'site' before passing to hashlib.sha1 --- frappe/commands/site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 3716a0b0bd..6dc8c13311 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -36,7 +36,7 @@ def _new_site(db_name, site, mariadb_root_username=None, mariadb_root_password=N """Install a new Frappe site""" if not db_name: - db_name = hashlib.sha1(site).hexdigest()[:16] + db_name = hashlib.sha1(site.encode()).hexdigest()[:16] from frappe.installer import install_db, make_site_dirs from frappe.installer import install_app as _install_app From 73a34c2234ac65b81f89f47fb3becc1922e697e7 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:44:37 +0530 Subject: [PATCH 03/13] Use absolute import to import frappe.utils.background_jobs --- frappe/utils/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index 211bef028c..7fe78973d6 100755 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -18,7 +18,7 @@ import MySQLdb import frappe.utils from frappe.utils import get_sites from datetime import datetime -from background_jobs import enqueue, get_jobs, queue_timeout +from frappe.utils.background_jobs import enqueue, get_jobs, queue_timeout from frappe.limits import has_expired from frappe.utils.data import get_datetime, now_datetime from frappe.core.doctype.user.user import STANDARD_USERS From 5313c2b2fe693be23b568cae1aa401193e131cbd Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Mon, 7 Aug 2017 23:58:41 +0530 Subject: [PATCH 04/13] Use string.ascii_letters instead of string.letters --- frappe/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index 5435e4f279..2c5b21b812 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -126,7 +126,7 @@ def random_string(length): """generate a random string""" import string from random import choice - return ''.join([choice(string.letters + string.digits) for i in range(length)]) + return ''.join([choice(string.ascii_letters + string.digits) for i in range(length)]) def has_gravatar(email): From 127accb54a9c2c7e0e0ff167f39c8f436dd3ca5b Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 10:50:20 +0530 Subject: [PATCH 05/13] Use abslute imports in frappe/__init__.py --- frappe/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a4c721c8ab..13c09a069e 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -164,7 +164,7 @@ def connect(site=None, db_name=None): :param site: If site is given, calls `frappe.init`. :param db_name: Optional. Will use from `site_config.json`.""" - from database import Database + from frappe.database import Database if site: init(site) local.db = Database(user=db_name or local.conf.db_name) @@ -235,8 +235,8 @@ def cache(): def get_traceback(): """Returns error traceback.""" - import utils - return utils.get_traceback() + from frappe.utils import get_traceback + return get_traceback() def errprint(msg): """Log error. This is sent back as `exc` in response. @@ -268,7 +268,7 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, :param raise_exception: [optional] Raise given exception and show message. :param as_table: [optional] If `msg` is a list of lists, render as HTML table. """ - from utils import encode + from frappe.utils import encode out = _dict(message=msg) @@ -421,8 +421,8 @@ def sendmail(recipients=[], sender="", subject="No Subject", message="No Message if not delayed: now = True - import email.queue - email.queue.send(recipients=recipients, sender=sender, + from frappe.email import queue + queue.send(recipients=recipients, sender=sender, subject=subject, message=message, text_content=text_content, reference_doctype = doctype or reference_doctype, reference_name = name or reference_name, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, unsubscribe_message=unsubscribe_message, @@ -488,7 +488,7 @@ def clear_cache(user=None, doctype=None): elif user: frappe.sessions.clear_cache(user) else: # everything - import translate + from frappe import translate frappe.sessions.clear_cache() translate.clear_cache() reset_metadata_version() From f2742b5eac413f73264d89051fe47f8cc65f256b Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 11:03:06 +0530 Subject: [PATCH 06/13] Encode string before passing to hashlib.sha224 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a4c721c8ab..c3d5d1aacd 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -576,7 +576,7 @@ def generate_hash(txt=None, length=None): """Generates random hash for given text + current timestamp + random string.""" import hashlib, time from .utils import random_string - digest = hashlib.sha224((txt or "") + repr(time.time()) + repr(random_string(8))).hexdigest() + digest = hashlib.sha224(((txt or "") + repr(time.time()) + repr(random_string(8))).encode()).hexdigest() if length: digest = digest[:length] return digest From 769338f136ccbafc23bd1e948c0b311423b428f3 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 11:43:23 +0530 Subject: [PATCH 07/13] Replaced all instances of basestring with six.string_types --- frappe/__init__.py | 8 ++++---- frappe/client.py | 14 +++++++------- frappe/contacts/doctype/address/address.py | 4 ++-- frappe/core/doctype/communication/email.py | 9 +++++---- frappe/core/doctype/communication/feed.py | 3 ++- frappe/core/doctype/file/file.py | 4 ++-- .../core/doctype/sms_settings/sms_settings.py | 3 ++- frappe/core/page/data_import_tool/exporter.py | 3 ++- frappe/core/page/data_import_tool/importer.py | 4 ++-- frappe/database.py | 14 +++++++------- .../desk/doctype/desktop_icon/desktop_icon.py | 6 +++--- frappe/desk/doctype/event/event.py | 3 ++- frappe/desk/form/linked_with.py | 3 ++- frappe/desk/form/run_method.py | 4 ++-- frappe/desk/form/utils.py | 3 ++- frappe/desk/page/setup_wizard/setup_wizard.py | 7 ++++--- frappe/desk/query_report.py | 19 ++++++++++--------- frappe/desk/reportview.py | 16 ++++++++-------- frappe/desk/search.py | 3 ++- .../email/doctype/email_alert/email_alert.py | 3 ++- .../doctype/standard_reply/standard_reply.py | 3 ++- frappe/email/email_body.py | 6 +++--- frappe/email/queue.py | 8 ++++---- frappe/frappeclient.py | 4 ++-- frappe/handler.py | 3 ++- frappe/integrations/utils.py | 3 ++- frappe/limits.py | 3 ++- frappe/model/base_document.py | 8 ++++---- frappe/model/db_query.py | 18 +++++++++--------- frappe/model/delete_doc.py | 3 ++- frappe/model/document.py | 6 +++--- frappe/model/mapper.py | 3 ++- frappe/model/naming.py | 5 +++-- frappe/model/utils/user_settings.py | 4 ++-- frappe/patches/v5_0/bookmarks_to_stars.py | 3 ++- frappe/permissions.py | 5 +++-- .../pages/integrations/razorpay_checkout.py | 3 ++- frappe/tests/test_permissions.py | 3 ++- frappe/translate.py | 6 +++--- frappe/twofactor.py | 5 +++-- frappe/utils/__init__.py | 8 ++++---- frappe/utils/background_jobs.py | 5 +++-- frappe/utils/csvutils.py | 4 ++-- frappe/utils/data.py | 12 ++++++------ frappe/utils/dateutils.py | 3 ++- frappe/utils/formatters.py | 3 ++- frappe/utils/html_utils.py | 3 ++- frappe/utils/make_random.py | 3 ++- frappe/utils/oauth.py | 5 +++-- frappe/utils/scheduler.py | 3 ++- frappe/utils/verified_command.py | 3 ++- frappe/utils/xlsxutils.py | 4 ++-- frappe/www/printview.py | 11 ++++++----- 53 files changed, 167 insertions(+), 135 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a4c721c8ab..ff66967abe 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -6,7 +6,7 @@ globals attached to frappe module """ from __future__ import unicode_literals, print_function -from six import iteritems, text_type +from six import iteritems, text_type, string_types from werkzeug.local import Local, release_local import os, sys, importlib, inspect, json @@ -61,7 +61,7 @@ def as_unicode(text, encoding='utf-8'): return text elif text==None: return '' - elif isinstance(text, basestring): + elif isinstance(text, string_types): return text_type(text, encoding) else: return text_type(text) @@ -533,7 +533,7 @@ def has_website_permission(doc=None, ptype='read', user=None, verbose=False, doc user = session.user if doc: - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = get_doc(doctype, doc) doctype = doc.doctype @@ -903,7 +903,7 @@ def get_attr(method_string): def call(fn, *args, **kwargs): """Call a function and match arguments.""" - if isinstance(fn, basestring): + if isinstance(fn, string_types): fn = get_attr(fn) if hasattr(fn, 'fnargs'): diff --git a/frappe/client.py b/frappe/client.py index fafa535e0e..f257f6abbe 100644 --- a/frappe/client.py +++ b/frappe/client.py @@ -8,7 +8,7 @@ import frappe.model import frappe.utils import json, os -from six import iteritems +from six import iteritems, string_types ''' Handle RESTful requests that are mapped to the `/api/resource` route. @@ -92,7 +92,7 @@ def set_value(doctype, name, fieldname, value=None): if not value: values = fieldname - if isinstance(fieldname, basestring): + if isinstance(fieldname, string_types): try: values = json.loads(fieldname) except ValueError: @@ -118,7 +118,7 @@ def insert(doc=None): '''Insert a document :param doc: JSON or dict object to be inserted''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) if doc.get("parent") and doc.get("parenttype"): @@ -136,7 +136,7 @@ def insert_many(docs=None): '''Insert multiple documents :param docs: JSON or list of dict objects to be inserted in one request''' - if isinstance(docs, basestring): + if isinstance(docs, string_types): docs = json.loads(docs) out = [] @@ -162,7 +162,7 @@ def save(doc): '''Update (save) an existing document :param doc: JSON or dict object with the properties of the document to be updated''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) doc = frappe.get_doc(doc).save() @@ -183,7 +183,7 @@ def submit(doc): '''Submit a document :param doc: JSON or dict object to be submitted remotely''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) doc = frappe.get_doc(doc) @@ -221,7 +221,7 @@ def make_width_property_setter(doc): '''Set width Property Setter :param doc: Property Setter document with `width` property''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) if doc["doctype"]=="Property Setter" and doc["property"]=="width": frappe.get_doc(doc).insert(ignore_permissions = True) diff --git a/frappe/contacts/doctype/address/address.py b/frappe/contacts/doctype/address/address.py index 33a01f3192..18e51f3a61 100644 --- a/frappe/contacts/doctype/address/address.py +++ b/frappe/contacts/doctype/address/address.py @@ -13,7 +13,7 @@ from jinja2 import TemplateSyntaxError from frappe.utils.user import is_website_user from frappe.model.naming import make_autoname from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links -from six import iteritems +from six import iteritems, string_types class Address(Document): @@ -115,7 +115,7 @@ def get_territory_from_address(address): if not address: return - if isinstance(address, basestring): + if isinstance(address, string_types): address = frappe.get_doc("Address", address) territory = None diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 3af3def992..cbc9c5a9bb 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals, absolute_import from six.moves import range +from six import string_types import frappe import json from email.utils import formataddr @@ -71,7 +72,7 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = # if no reference given, then send it against the communication comm.db_set(dict(reference_doctype='Communication', reference_name=comm.name)) - if isinstance(attachments, basestring): + if isinstance(attachments, string_types): attachments = json.loads(attachments) # if not committed, delayed task doesn't find the communication @@ -250,11 +251,11 @@ def prepare_to_notify(doc, print_html=None, print_format=None, attachments=None) print_format=print_format, html=print_html)) if attachments: - if isinstance(attachments, basestring): + if isinstance(attachments, string_types): attachments = json.loads(attachments) for a in attachments: - if isinstance(a, basestring): + if isinstance(a, string_types): # is it a filename? try: file = get_file(a) @@ -342,7 +343,7 @@ def add_attachments(name, attachments): # loop through attachments for a in attachments: - if isinstance(a, basestring): + if isinstance(a, string_types): attach = frappe.db.get_value("File", {"name":a}, ["file_name", "file_url", "is_private"], as_dict=1) diff --git a/frappe/core/doctype/communication/feed.py b/frappe/core/doctype/communication/feed.py index 2d939447cd..40d4418c5f 100644 --- a/frappe/core/doctype/communication/feed.py +++ b/frappe/core/doctype/communication/feed.py @@ -9,6 +9,7 @@ from frappe.utils import get_fullname from frappe import _ from frappe.core.doctype.communication.comment import add_info_comment from frappe.core.doctype.authentication_log.authentication_log import add_authentication_log +from six import string_types def update_feed(doc, method=None): "adds a new communication with comment_type='Updated'" @@ -25,7 +26,7 @@ def update_feed(doc, method=None): feed = doc.get_feed() if feed: - if isinstance(feed, basestring): + if isinstance(feed, string_types): feed = {"subject": feed} feed = frappe._dict(feed) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index f9b65e6556..4be9693125 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -21,7 +21,7 @@ from frappe import _ from frappe.utils.nestedset import NestedSet from frappe.utils import strip, get_files_path from PIL import Image, ImageOps -from six import StringIO +from six import StringIO, string_types from six.moves.urllib.parse import unquote import zipfile @@ -305,7 +305,7 @@ def create_new_folder(file_name, folder): @frappe.whitelist() def move_file(file_list, new_parent, old_parent): - if isinstance(file_list, basestring): + if isinstance(file_list, string_types): file_list = json.loads(file_list) for file_obj in file_list: diff --git a/frappe/core/doctype/sms_settings/sms_settings.py b/frappe/core/doctype/sms_settings/sms_settings.py index a8b59beffa..70f5feebbc 100644 --- a/frappe/core/doctype/sms_settings/sms_settings.py +++ b/frappe/core/doctype/sms_settings/sms_settings.py @@ -9,6 +9,7 @@ from frappe import _, throw, msgprint from frappe.utils import nowdate from frappe.model.document import Document +from six import string_types class SMSSettings(Document): pass @@ -55,7 +56,7 @@ def get_contact_number(contact_name, ref_doctype, ref_name): def send_sms(receiver_list, msg, sender_name = '', success_msg = True): import json - if isinstance(receiver_list, basestring): + if isinstance(receiver_list, string_types): receiver_list = json.loads(receiver_list) if not isinstance(receiver_list, list): receiver_list = [receiver_list] diff --git a/frappe/core/page/data_import_tool/exporter.py b/frappe/core/page/data_import_tool/exporter.py index caa6ae90ef..4f7bf8a067 100644 --- a/frappe/core/page/data_import_tool/exporter.py +++ b/frappe/core/page/data_import_tool/exporter.py @@ -10,6 +10,7 @@ import re, csv, os from frappe.utils.csvutils import UnicodeWriter from frappe.utils import cstr, formatdate, format_datetime from frappe.core.page.data_import_tool.data_import_tool import get_data_keys +from six import string_types reflags = { "I":re.I, @@ -29,7 +30,7 @@ def get_template(doctype=None, parent_doctype=None, all_doctypes="No", with_data select_columns = json.loads(select_columns); docs_to_export = {} if doctype: - if isinstance(doctype, basestring): + if isinstance(doctype, string_types): doctype = [doctype]; if len(doctype) > 1: docs_to_export = doctype[1] diff --git a/frappe/core/page/data_import_tool/importer.py b/frappe/core/page/data_import_tool/importer.py index 308cef8f55..ae30757c34 100644 --- a/frappe/core/page/data_import_tool/importer.py +++ b/frappe/core/page/data_import_tool/importer.py @@ -17,7 +17,7 @@ from frappe.utils.file_manager import save_url from frappe.utils import cint, cstr, flt, getdate, get_datetime, get_url from frappe.core.page.data_import_tool.data_import_tool import get_data_keys -from six import text_type +from six import text_type, string_types @frappe.whitelist() def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, no_email=True, overwrite=None, @@ -119,7 +119,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": - if d[fieldname] and isinstance(d[fieldname], basestring): + if d[fieldname] and isinstance(d[fieldname], string_types): d[fieldname] = getdate(parse_date(d[fieldname])) elif fieldtype == "Datetime": if d[fieldname]: diff --git a/frappe/database.py b/frappe/database.py index b702a8c53d..34a70699d1 100644 --- a/frappe/database.py +++ b/frappe/database.py @@ -18,7 +18,7 @@ import redis import frappe.model.meta from frappe.utils import now, get_datetime, cstr from frappe import _ -from six import text_type, binary_type +from six import text_type, binary_type, string_types from frappe.utils.global_search import sync_global_search from frappe.model.utils.link_count import flush_local_link_count from six import iteritems, text_type @@ -386,7 +386,7 @@ class Database: conditions.append(condition) - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = { "name": filters } for f in filters: @@ -451,7 +451,7 @@ class Database: user = frappe.db.get_values("User", "test@example.com", "*")[0] """ out = None - if cache and isinstance(filters, basestring) and \ + if cache and isinstance(filters, string_types) and \ (doctype, filters, fieldname) in self.value_cache: return self.value_cache[(doctype, filters, fieldname)] @@ -463,7 +463,7 @@ class Database: else: fields = fieldname if fieldname!="*": - if isinstance(fieldname, basestring): + if isinstance(fieldname, string_types): fields = [fieldname] else: fields = fieldname @@ -483,7 +483,7 @@ class Database: else: out = self.get_values_from_single(fields, filters, doctype, as_dict, debug, update) - if cache and isinstance(filters, basestring): + if cache and isinstance(filters, string_types): self.value_cache[(doctype, filters, fieldname)] = out return out @@ -789,7 +789,7 @@ class Database: :param dt: DocType name. :param dn: Document name or filter dict.""" - if isinstance(dt, basestring): + if isinstance(dt, string_types): if dt!="DocType" and dt==dn: return True # single always exists (!) try: @@ -854,7 +854,7 @@ class Database: add index `%s`(%s)""" % (doctype, index_name, ", ".join(fields))) def add_unique(self, doctype, fields, constraint_name=None): - if isinstance(fields, basestring): + if isinstance(fields, string_types): fields = [fields] if not constraint_name: constraint_name = "unique_" + "_".join(fields) diff --git a/frappe/desk/doctype/desktop_icon/desktop_icon.py b/frappe/desk/doctype/desktop_icon/desktop_icon.py index d4b4d2c1f5..1319ffba49 100644 --- a/frappe/desk/doctype/desktop_icon/desktop_icon.py +++ b/frappe/desk/doctype/desktop_icon/desktop_icon.py @@ -9,7 +9,7 @@ from frappe import _ import json import random from frappe.model.document import Document -from six import iteritems +from six import iteritems, string_types class DesktopIcon(Document): @@ -171,7 +171,7 @@ def add_user_icon(_doctype, _report=None, label=None, link=None, type='link', st @frappe.whitelist() def set_order(new_order, user=None): '''set new order by duplicating user icons (if user is set) or set global order''' - if isinstance(new_order, basestring): + if isinstance(new_order, string_types): new_order = json.loads(new_order) for i, module_name in enumerate(new_order): if module_name not in ('Explore',): @@ -228,7 +228,7 @@ def set_hidden_list(hidden_list, user=None): '''Sets property `hidden`=1 in **Desktop Icon** for given user. If user is None then it will set global values. It will also set the rest of the icons as shown (`hidden` = 0)''' - if isinstance(hidden_list, basestring): + if isinstance(hidden_list, string_types): hidden_list = json.loads(hidden_list) # set as hidden diff --git a/frappe/desk/doctype/event/event.py b/frappe/desk/doctype/event/event.py index b77b708ae6..0e97d78fb7 100644 --- a/frappe/desk/doctype/event/event.py +++ b/frappe/desk/doctype/event/event.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from six.moves import range +from six import string_types import frappe import json @@ -69,7 +70,7 @@ def send_event_digest(): def get_events(start, end, user=None, for_reminder=False, filters=None): if not user: user = frappe.session.user - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) roles = frappe.get_roles(user) events = frappe.db.sql("""select name, subject, description, color, diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 3a3e1d5a6b..e5192b1edb 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -7,10 +7,11 @@ from frappe.model.meta import is_single from frappe.modules import load_doctype_module import frappe.desk.form.meta import frappe.desk.form.load +from six import string_types @frappe.whitelist() def get_linked_docs(doctype, name, linkinfo=None, for_doctype=None): - if isinstance(linkinfo, basestring): + if isinstance(linkinfo, string_types): # additional fields are added in linkinfo linkinfo = json.loads(linkinfo) diff --git a/frappe/desk/form/run_method.py b/frappe/desk/form/run_method.py index 1253cc49b3..0a973c35ed 100644 --- a/frappe/desk/form/run_method.py +++ b/frappe/desk/form/run_method.py @@ -6,7 +6,7 @@ import json, inspect import frappe from frappe import _ from frappe.utils import cint -from six import text_type +from six import text_type, string_types @frappe.whitelist() def runserverobj(method, docs=None, dt=None, dn=None, arg=None, args=None): @@ -62,7 +62,7 @@ def make_csv_output(res, dt): for r in res: row = [] for v in r: - if isinstance(v, basestring): + if isinstance(v, string_types): v = v.encode("utf-8") row.append(v) writer.writerow(row) diff --git a/frappe/desk/form/utils.py b/frappe/desk/form/utils.py index cdb138b325..999a83a2fe 100644 --- a/frappe/desk/form/utils.py +++ b/frappe/desk/form/utils.py @@ -7,6 +7,7 @@ import frappe.desk.form.meta import frappe.desk.form.load from frappe import _ +from six import string_types @frappe.whitelist() def remove_attach(): @@ -65,7 +66,7 @@ def get_next(doctype, value, prev, filters=None, order_by="modified desc"): sort_field, sort_order = order_by.split(" ") if not filters: filters = [] - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) # condition based on sort order diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py index ad3108b67a..e0d8f721b4 100755 --- a/frappe/desk/page/setup_wizard/setup_wizard.py +++ b/frappe/desk/page/setup_wizard/setup_wizard.py @@ -11,6 +11,7 @@ from frappe.utils.file_manager import save_file from frappe.utils.password import update_password from werkzeug.useragents import UserAgent import install_fixtures +from six import string_types @frappe.whitelist() def setup_complete(args): @@ -127,14 +128,14 @@ def update_user_name(args): def process_args(args): if not args: args = frappe.local.form_dict - if isinstance(args, basestring): + if isinstance(args, string_types): args = json.loads(args) args = frappe._dict(args) # strip the whitespace for key, value in args.items(): - if isinstance(value, basestring): + if isinstance(value, string_types): args[key] = strip(value) return args @@ -204,7 +205,7 @@ def load_user_details(): def prettify_args(args): # remove attachments for key, val in args.items(): - if isinstance(val, basestring) and "data:image" in val: + if isinstance(val, string_types) and "data:image" in val: filename = val.split("data:image", 1)[0].strip(", ") size = round((len(val) * 3 / 4) / 1048576.0, 2) args[key] = "Image Attached: '{0}' of size {1} MB".format(filename, size) diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index 073576c437..d2b7591574 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -13,6 +13,7 @@ from frappe.model.utils import render_include from frappe.translate import send_translations import frappe.desk.reportview from frappe.permissions import get_role_permissions +from six import string_types def get_report_doc(report_name): doc = frappe.get_doc("Report", report_name) @@ -70,7 +71,7 @@ def run(report_name, filters=None, user=None): if not filters: filters = [] - if filters and isinstance(filters, basestring): + if filters and isinstance(filters, string_types): filters = json.loads(filters) if not frappe.has_permission(report.ref_doctype, "report"): @@ -127,13 +128,13 @@ def export_query(): if "csrf_token" in data: del data["csrf_token"] - if isinstance(data.get("filters"), basestring): + if isinstance(data.get("filters"), string_types): filters = json.loads(data["filters"]) - if isinstance(data.get("report_name"), basestring): + if isinstance(data.get("report_name"), string_types): report_name = data["report_name"] - if isinstance(data.get("file_format_type"), basestring): + if isinstance(data.get("file_format_type"), string_types): file_format_type = data["file_format_type"] - if isinstance(data.get("visible_idx"), basestring): + if isinstance(data.get("visible_idx"), string_types): visible_idx = json.loads(data.get("visible_idx")) else: visible_idx = None @@ -181,7 +182,7 @@ def add_total_row(result, columns, meta = None): has_percent = [] for i, col in enumerate(columns): fieldtype, options = None, None - if isinstance(col, basestring): + if isinstance(col, string_types): if meta: # get fieldtype from the meta field = meta.get_field(col) @@ -214,7 +215,7 @@ def add_total_row(result, columns, meta = None): total_row[i] = flt(total_row[i]) / len(result) first_col_fieldtype = None - if isinstance(columns[0], basestring): + if isinstance(columns[0], string_types): first_col = columns[0].split(":") if len(first_col) > 1: first_col_fieldtype = first_col[1].split("/")[0] @@ -319,7 +320,7 @@ def get_linked_doctypes(columns, data): for idx, col in enumerate(columns): df = columns_dict[idx] if df.get("fieldtype")=="Link": - if isinstance(col, basestring): + if isinstance(col, string_types): linked_doctypes[df["options"]] = idx else: # dict @@ -355,7 +356,7 @@ def get_columns_dict(columns): col_dict = frappe._dict() # string - if isinstance(col, basestring): + if isinstance(col, string_types): col = col.split(":") if len(col) > 1: if "/" in col[1]: diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index 0ce1d495f8..9474f6b7e8 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -10,7 +10,7 @@ import frappe.permissions import MySQLdb from frappe.model.db_query import DatabaseQuery from frappe import _ -from six import text_type +from six import text_type, string_types @frappe.whitelist() def get(): @@ -31,13 +31,13 @@ def get_form_params(): if "csrf_token" in data: del data["csrf_token"] - if isinstance(data.get("filters"), basestring): + if isinstance(data.get("filters"), string_types): data["filters"] = json.loads(data["filters"]) - if isinstance(data.get("fields"), basestring): + if isinstance(data.get("fields"), string_types): data["fields"] = json.loads(data["fields"]) - if isinstance(data.get("docstatus"), basestring): + if isinstance(data.get("docstatus"), string_types): data["docstatus"] = json.loads(data["docstatus"]) - if isinstance(data.get("save_user_settings"), basestring): + if isinstance(data.get("save_user_settings"), string_types): data["save_user_settings"] = json.loads(data["save_user_settings"]) else: data["save_user_settings"] = True @@ -341,7 +341,7 @@ def build_match_conditions(doctype, as_condition=True): return match_conditions def get_filters_cond(doctype, filters, conditions, ignore_permissions=None, with_match_conditions=False): - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) if filters: @@ -350,10 +350,10 @@ def get_filters_cond(doctype, filters, conditions, ignore_permissions=None, with filters = filters.items() flt = [] for f in filters: - if isinstance(f[1], basestring) and f[1][0] == '!': + if isinstance(f[1], string_types) and f[1][0] == '!': flt.append([doctype, f[0], '!=', f[1][1:]]) else: - value = frappe.db.escape(f[1]) if isinstance(f[1], basestring) else f[1] + value = frappe.db.escape(f[1]) if isinstance(f[1], string_types) else f[1] flt.append([doctype, f[0], '=', value]) query = DatabaseQuery(doctype) diff --git a/frappe/desk/search.py b/frappe/desk/search.py index d9f881e3db..e9c5c62bd5 100644 --- a/frappe/desk/search.py +++ b/frappe/desk/search.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe, json from frappe.utils import cstr, unique from frappe import _ +from six import string_types # this is called by the Link Field @frappe.whitelist() @@ -18,7 +19,7 @@ def search_link(doctype, txt, query=None, filters=None, page_length=20, searchfi @frappe.whitelist() def search_widget(doctype, txt, query=None, searchfield=None, start=0, page_length=10, filters=None, filter_fields=None, as_dict=False): - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) meta = frappe.get_meta(doctype) diff --git a/frappe/email/doctype/email_alert/email_alert.py b/frappe/email/doctype/email_alert/email_alert.py index f4bce6f5cd..8ef2423299 100755 --- a/frappe/email/doctype/email_alert/email_alert.py +++ b/frappe/email/doctype/email_alert/email_alert.py @@ -12,6 +12,7 @@ from frappe.utils.data import parse_val from frappe.utils.jinja import validate_template from frappe.modules.utils import export_module_json, get_doc_module from markdown2 import markdown +from six import string_types class EmailAlert(Document): def autoname(self): @@ -210,7 +211,7 @@ def trigger_email_alerts(doc, method=None): def evaluate_alert(doc, alert, event): from jinja2 import TemplateError try: - if isinstance(alert, basestring): + if isinstance(alert, string_types): alert = frappe.get_doc("Email Alert", alert) context = get_context(doc) diff --git a/frappe/email/doctype/standard_reply/standard_reply.py b/frappe/email/doctype/standard_reply/standard_reply.py index 5ca40005a2..17828cb352 100755 --- a/frappe/email/doctype/standard_reply/standard_reply.py +++ b/frappe/email/doctype/standard_reply/standard_reply.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe, json from frappe.model.document import Document from frappe.utils.jinja import validate_template +from six import string_types class StandardReply(Document): def validate(self): @@ -13,7 +14,7 @@ class StandardReply(Document): @frappe.whitelist() def get_standard_reply(template_name, doc): '''Returns the processed HTML of a standard reply with the given doc''' - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = json.loads(doc) standard_reply = frappe.get_doc("Standard Reply", template_name) diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index 12deec3427..b589986bc0 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -8,7 +8,7 @@ from frappe.email.smtp import get_outgoing_email_account from frappe.utils import (get_url, scrub_urls, strip, expand_relative_urls, cint, split_emails, to_markdown, markdown, encode, random_string, parse_addr) import email.utils -from six import iteritems, text_type +from six import iteritems, text_type, string_types from email.mime.multipart import MIMEMultipart @@ -54,7 +54,7 @@ class EMail: from email import Charset Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8') - if isinstance(recipients, basestring): + if isinstance(recipients, string_types): recipients = recipients.replace(';', ',').replace('\n', '') recipients = split_emails(recipients) @@ -432,7 +432,7 @@ def get_header(header=None): if not header: return None - if isinstance(header, basestring): + if isinstance(header, string_types): # header = 'My Title' header = [header, None] if len(header) == 1: diff --git a/frappe/email/queue.py b/frappe/email/queue.py index e3e2267f6e..975e36f23f 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -15,7 +15,7 @@ from frappe.utils import get_url, nowdate, encode, now_datetime, add_days, split from frappe.utils.file_manager import get_file from rq.timeouts import JobTimeoutException from frappe.utils.scheduler import log -from six import text_type +from six import text_type, string_types class EmailLimitCrossedError(frappe.ValidationError): pass @@ -55,10 +55,10 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content= if not recipients and not cc: return - if isinstance(recipients, basestring): + if isinstance(recipients, string_types): recipients = split_emails(recipients) - if isinstance(cc, basestring): + if isinstance(cc, string_types): cc = split_emails(cc) if isinstance(send_after, int): @@ -471,7 +471,7 @@ def prepare_message(email, recipient, recipients_list): pass else: if email.expose_recipients == "footer": - if isinstance(email.show_as_cc, basestring): + if isinstance(email.show_as_cc, string_types): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join([e for e in email_sent_to if e in email.show_as_cc]) diff --git a/frappe/frappeclient.py b/frappe/frappeclient.py index 30c71956dd..b92463f474 100644 --- a/frappe/frappeclient.py +++ b/frappe/frappeclient.py @@ -2,7 +2,7 @@ from __future__ import print_function import requests import json import frappe -from six import iteritems +from six import iteritems, string_types ''' FrappeClient is a library that helps you connect with other frappe systems @@ -49,7 +49,7 @@ class FrappeClient(object): def get_list(self, doctype, fields='"*"', filters=None, limit_start=0, limit_page_length=0): """Returns list of records of a particular type""" - if not isinstance(fields, basestring): + if not isinstance(fields, string_types): fields = json.dumps(fields) params = { "fields": fields, diff --git a/frappe/handler.py b/frappe/handler.py index 4845b4d725..98d88297fb 100755 --- a/frappe/handler.py +++ b/frappe/handler.py @@ -11,6 +11,7 @@ import frappe.utils.file_manager import frappe.desk.form.run_method from frappe.utils.response import build_response from werkzeug.wrappers import Response +from six import string_types def handle(): """handle request""" @@ -63,7 +64,7 @@ def is_whitelisted(method): # strictly sanitize form_dict # escapes html characters like <> except for predefined tags like a, b, ul etc. for key, value in frappe.form_dict.items(): - if isinstance(value, basestring): + if isinstance(value, string_types): frappe.form_dict[key] = frappe.utils.sanitize_html(value) else: diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index 8215eefd7b..c79a190e94 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe import json from six.moves.urllib.parse import parse_qs +from six import string_types from frappe.utils import get_request_session from frappe import _ @@ -49,7 +50,7 @@ def make_post_request(url, auth=None, headers=None, data=None): raise exc def create_request_log(data, integration_type, service_name, name=None): - if isinstance(data, basestring): + if isinstance(data, string_types): data = json.loads(data) integration_request = frappe.get_doc({ diff --git a/frappe/limits.py b/frappe/limits.py index 0f597e445f..d804aab54b 100755 --- a/frappe/limits.py +++ b/frappe/limits.py @@ -7,6 +7,7 @@ from frappe.utils.data import formatdate from frappe.utils.user import get_enabled_system_users, disable_users import os, subprocess, urllib from six.moves.urllib.parse import parse_qsl, urlsplit, urlunsplit +from six import string_types class SiteExpiredError(frappe.ValidationError): http_status_code = 417 @@ -162,7 +163,7 @@ def update_limits(limits_dict): def clear_limit(key): '''Remove a limit option from site_config''' limits = get_limits() - to_clear = [key] if isinstance(key, basestring) else key + to_clear = [key] if isinstance(key, string_types) else key for key in to_clear: if key in limits: del limits[key] diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 0151feac8e..0babe8ca53 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -2,7 +2,7 @@ # MIT License. See license.txt from __future__ import unicode_literals -from six import reraise as raise_, iteritems +from six import reraise as raise_, iteritems, string_types import frappe, sys from frappe import _ from frappe.utils import (cint, flt, now, cstr, strip_html, getdate, get_datetime, to_timedelta, @@ -610,7 +610,7 @@ class BaseDocument(object): return for fieldname, value in self.get_valid_dict().items(): - if not value or not isinstance(value, basestring): + if not value or not isinstance(value, string_types): continue value = frappe.as_unicode(value) @@ -673,7 +673,7 @@ class BaseDocument(object): :param parentfield: If fieldname is in child table.""" from frappe.model.meta import get_field_precision - if parentfield and not isinstance(parentfield, basestring): + if parentfield and not isinstance(parentfield, string_types): parentfield = parentfield.parentfield cache_key = parentfield or "main" @@ -831,7 +831,7 @@ def _filter(data, filters, limit=None): fval = ("not None", fval) elif fval is False: fval = ("None", fval) - elif isinstance(fval, basestring) and fval.startswith("^"): + elif isinstance(fval, string_types) and fval.startswith("^"): fval = ("^", fval[1:]) else: fval = ("=", fval) diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 205fd3a1e7..8dde636731 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals -from six import iteritems +from six import iteritems, string_types """build query for doclistview and return results""" @@ -47,7 +47,7 @@ class DatabaseQuery(object): filters, fields = fields, filters elif fields and isinstance(filters, list) \ - and len(filters) > 1 and isinstance(filters[0], basestring): + and len(filters) > 1 and isinstance(filters[0], string_types): # if `filters` is a list of strings, its probably fields filters, fields = fields, filters @@ -157,7 +157,7 @@ class DatabaseQuery(object): def parse_args(self): """Convert fields and filters from strings to list, dicts""" - if isinstance(self.fields, basestring): + if isinstance(self.fields, string_types): if self.fields == "*": self.fields = ["*"] else: @@ -168,7 +168,7 @@ class DatabaseQuery(object): for filter_name in ["filters", "or_filters"]: filters = getattr(self, filter_name) - if isinstance(filters, basestring): + if isinstance(filters, string_types): filters = json.loads(filters) if isinstance(filters, dict): @@ -230,7 +230,7 @@ class DatabaseQuery(object): # remove from filters to_remove = [] for each in self.filters: - if isinstance(each, basestring): + if isinstance(each, string_types): each = [each] for element in each: @@ -264,7 +264,7 @@ class DatabaseQuery(object): filters = [filters] for f in filters: - if isinstance(f, basestring): + if isinstance(f, string_types): conditions.append(f) else: conditions.append(self.prepare_filter_condition(f)) @@ -331,12 +331,12 @@ class DatabaseQuery(object): value = get_time(f.value).strftime("%H:%M:%S.%f") fallback = "'00:00:00'" - elif f.operator.lower() in ("like", "not like") or (isinstance(f.value, basestring) and + elif f.operator.lower() in ("like", "not like") or (isinstance(f.value, string_types) and (not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])): value = "" if f.value==None else f.value fallback = '""' - if f.operator.lower() in ("like", "not like") and isinstance(value, basestring): + if f.operator.lower() in ("like", "not like") and isinstance(value, string_types): # because "like" uses backslash (\) for escaping value = value.replace("\\", "\\\\").replace("%", "%%") @@ -345,7 +345,7 @@ class DatabaseQuery(object): fallback = 0 # put it inside double quotes - if isinstance(value, basestring) and not f.operator.lower() == 'between': + if isinstance(value, string_types) and not f.operator.lower() == 'between': value = '"{0}"'.format(frappe.db.escape(value, percent=False)) if (self.ignore_ifnull diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index 3e4f60c7f6..03cfca6652 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -12,6 +12,7 @@ from frappe.utils.password import delete_all_passwords_for from frappe import _ from frappe.model.naming import revert_series_if_last from frappe.utils.global_search import delete_for_document +from six import string_types def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False, flags=None, ignore_on_trash=False): @@ -26,7 +27,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa name = frappe.form_dict.get('dn') names = name - if isinstance(name, basestring): + if isinstance(name, string_types): names = [name] for name in names or []: diff --git a/frappe/model/document.py b/frappe/model/document.py index 3e8db22802..2cab4c0b4c 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -9,7 +9,7 @@ from frappe.utils import flt, cstr, now, get_datetime_str, file_lock from frappe.utils.background_jobs import enqueue from frappe.model.base_document import BaseDocument, get_controller from frappe.model.naming import set_new_name -from six import iteritems +from six import iteritems, string_types from werkzeug.exceptions import NotFound, Forbidden import hashlib, json from frappe.model import optional_fields @@ -41,7 +41,7 @@ def get_doc(arg1, arg2=None): """ if isinstance(arg1, BaseDocument): return arg1 - elif isinstance(arg1, basestring): + elif isinstance(arg1, string_types): doctype = arg1 else: doctype = arg1.get("doctype") @@ -67,7 +67,7 @@ class Document(BaseDocument): self._default_new_docs = {} self.flags = frappe._dict() - if arg1 and isinstance(arg1, basestring): + if arg1 and isinstance(arg1, string_types): if not arg2: # single self.doctype = self.name = arg1 diff --git a/frappe/model/mapper.py b/frappe/model/mapper.py index 72a9a77e3c..8f77668204 100644 --- a/frappe/model/mapper.py +++ b/frappe/model/mapper.py @@ -6,6 +6,7 @@ import frappe, json from frappe import _ from frappe.utils import cstr from frappe.model import default_fields +from six import string_types @frappe.whitelist() def make_mapped_doc(method, source_name, selected_children=None): @@ -43,7 +44,7 @@ def get_mapped_doc(from_doctype, from_docname, table_maps, target_doc=None, # main if not target_doc: target_doc = frappe.new_doc(table_maps[from_doctype]["doctype"]) - elif isinstance(target_doc, basestring): + elif isinstance(target_doc, string_types): target_doc = frappe.get_doc(json.loads(target_doc)) if not ignore_permissions and not target_doc.has_permission("create"): diff --git a/frappe/model/naming.py b/frappe/model/naming.py index c47422c3ec..6ccc5a0a19 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -6,6 +6,7 @@ import frappe from frappe import _ from frappe.utils import now_datetime, cint import re +from six import string_types def set_new_name(doc): """ @@ -99,7 +100,7 @@ def make_autoname(key='', doctype='', doc=''): def parse_naming_series(parts, doctype= '', doc = ''): n = '' - if isinstance(parts, basestring): + if isinstance(parts, string_types): parts = parts.split('.') series_set = False @@ -123,7 +124,7 @@ def parse_naming_series(parts, doctype= '', doc = ''): part = doc.get(e) else: part = e - if isinstance(part, basestring): + if isinstance(part, string_types): n+=part return n diff --git a/frappe/model/utils/user_settings.py b/frappe/model/utils/user_settings.py index 1034334049..bbbd9298f7 100644 --- a/frappe/model/utils/user_settings.py +++ b/frappe/model/utils/user_settings.py @@ -2,7 +2,7 @@ # such as page_limit, filters, last_view import frappe, json -from six import iteritems +from six import iteritems, string_types def get_user_settings(doctype, for_update=False): @@ -27,7 +27,7 @@ def update_user_settings(doctype, user_settings, for_update=False): else: current = json.loads(get_user_settings(doctype, for_update = True)) - if isinstance(current, basestring): + if isinstance(current, string_types): # corrupt due to old code, remove this in a future release current = {} diff --git a/frappe/patches/v5_0/bookmarks_to_stars.py b/frappe/patches/v5_0/bookmarks_to_stars.py index 603697a1b7..048d059701 100644 --- a/frappe/patches/v5_0/bookmarks_to_stars.py +++ b/frappe/patches/v5_0/bookmarks_to_stars.py @@ -3,6 +3,7 @@ import json import frappe import frappe.defaults from frappe.desk.like import _toggle_like +from six import string_types def execute(): for user in frappe.get_all("User"): @@ -12,7 +13,7 @@ def execute(): if not bookmarks: continue - if isinstance(bookmarks, basestring): + if isinstance(bookmarks, string_types): bookmarks = json.loads(bookmarks) for opts in bookmarks: diff --git a/frappe/permissions.py b/frappe/permissions.py index 29f223d08e..2dc57253e9 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals, print_function from six.moves import range +from six import string_types import frappe, copy, json from frappe import _, msgprint from frappe.utils import cint @@ -51,7 +52,7 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): ["read" if ptype in ("email", "print") else ptype]) if doc: - doc_name = doc if isinstance(doc, basestring) else doc.name + doc_name = doc if isinstance(doc, string_types) else doc.name if doc_name in shared: if verbose: print("Shared") if ptype in ("read", "write", "share") or meta.permissions[0].get(ptype): @@ -75,7 +76,7 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): perm = True if doc: - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = frappe.get_doc(meta.name, doc) owner_perm = user_perm = controller_perm = None diff --git a/frappe/templates/pages/integrations/razorpay_checkout.py b/frappe/templates/pages/integrations/razorpay_checkout.py index d37fef21e6..3af552d6a6 100644 --- a/frappe/templates/pages/integrations/razorpay_checkout.py +++ b/frappe/templates/pages/integrations/razorpay_checkout.py @@ -5,6 +5,7 @@ import frappe from frappe import _ from frappe.utils import flt, cint import json +from six import string_types no_cache = 1 no_sitemap = 1 @@ -39,7 +40,7 @@ def get_api_key(): def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname): data = {} - if isinstance(options, basestring): + if isinstance(options, string_types): data = json.loads(options) data.update({ diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index d54c484eba..fecae8c6aa 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -14,6 +14,7 @@ from frappe.permissions import (add_user_permission, remove_user_permission, get_valid_perms) from frappe.core.page.permission_manager.permission_manager import update, reset from frappe.test_runner import make_test_records_for_doctype +from six import string_types test_records = frappe.get_test_records('Blog Post') @@ -361,7 +362,7 @@ def set_user_permission_doctypes(doctypes, role, apply_user_permissions, user_permission_doctypes): user_permission_doctypes = None if not user_permission_doctypes else json.dumps(user_permission_doctypes) - if isinstance(doctypes, basestring): + if isinstance(doctypes, string_types): doctypes = [doctypes] for doctype in doctypes: diff --git a/frappe/translate.py b/frappe/translate.py index ea1c1891e8..ab5ff018a6 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals, print_function -from six import iteritems, text_type +from six import iteritems, text_type, string_types """ frappe.translate @@ -359,7 +359,7 @@ def get_messages_from_workflow(doctype=None, app_name=None): else: fixtures = frappe.get_hooks('fixtures', app_name=app_name) or [] for fixture in fixtures: - if isinstance(fixture, basestring) and fixture == 'Worflow': + if isinstance(fixture, string_types) and fixture == 'Worflow': workflows = frappe.get_all('Workflow') break elif isinstance(fixture, dict) and fixture.get('dt', fixture.get('doctype')) == 'Workflow': @@ -394,7 +394,7 @@ def get_messages_from_custom_fields(app_name): custom_fields = [] for fixture in fixtures: - if isinstance(fixture, basestring) and fixture == 'Custom Field': + if isinstance(fixture, string_types) and fixture == 'Custom Field': custom_fields = frappe.get_all('Custom Field', fields=['name','label', 'description', 'fieldtype', 'options']) break elif isinstance(fixture, dict) and fixture.get('dt', fixture.get('doctype')) == 'Custom Field': diff --git a/frappe/twofactor.py b/frappe/twofactor.py index bb796fd296..2e2562964a 100644 --- a/frappe/twofactor.py +++ b/frappe/twofactor.py @@ -12,6 +12,7 @@ from pyqrcode import create as qrcreate from StringIO import StringIO from base64 import b64encode, b32encode from frappe.utils import get_url, get_datetime, time_diff_in_seconds +from six import string_types class ExpiredLoginException(Exception): pass @@ -73,7 +74,7 @@ def cache_2fa_data(user, token, otp_secret, tmp_id): def two_factor_is_enabled_for_(user): '''Check if 2factor is enabled for user.''' - if isinstance(user, basestring): + if isinstance(user, string_types): user = frappe.get_doc('User', user) roles = [frappe.db.escape(d.role) for d in user.roles or []] @@ -357,7 +358,7 @@ def delete_all_barcodes_for_users(): def should_remove_barcode_image(barcode): '''Check if it's time to delete barcode image from server. ''' - if isinstance(barcode, basestring): + if isinstance(barcode, string_types): barcode = frappe.get_doc('File', barcode) lifespan = frappe.db.get_value('System Settings', 'System Settings', 'lifespan_qrcode_image') if time_diff_in_seconds(get_datetime(), barcode.creation) > int(lifespan): diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index 5435e4f279..86f5ebac1d 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -14,7 +14,7 @@ from email.utils import parseaddr, formataddr # utility functions like cint, int, flt, etc. from frappe.utils.data import * from six.moves.urllib.parse import quote -from six import text_type +from six import text_type, string_types default_fields = ['doctype', 'name', 'owner', 'creation', 'modified', 'modified_by', 'parent', 'parentfield', 'parenttype', 'idx', 'docstatus'] @@ -63,7 +63,7 @@ def get_formatted_email(user): def extract_email_id(email): """fetch only the email part of the Email Address""" email_id = parse_addr(email)[1] - if email_id and isinstance(email_id, basestring) and not isinstance(email_id, text_type): + if email_id and isinstance(email_id, string_types) and not isinstance(email_id, text_type): email_id = email_id.decode("utf-8", "ignore") return email_id @@ -305,14 +305,14 @@ def get_request_site_address(full_address=False): def encode_dict(d, encoding="utf-8"): for key in d: - if isinstance(d[key], basestring) and isinstance(d[key], text_type): + if isinstance(d[key], string_types) and isinstance(d[key], text_type): d[key] = d[key].encode(encoding) return d def decode_dict(d, encoding="utf-8"): for key in d: - if isinstance(d[key], basestring) and not isinstance(d[key], text_type): + if isinstance(d[key], string_types) and not isinstance(d[key], text_type): d[key] = d[key].decode(encoding, "ignore") return d diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index e9c0bc8406..234ba3b929 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -8,6 +8,7 @@ import frappe import MySQLdb import os, socket, time from frappe import _ +from six import string_types default_timeout = 300 queue_timeout = { @@ -60,7 +61,7 @@ def execute_job(site, method, event, job_name, kwargs, user=None, async=True, re if user: frappe.set_user(user) - if isinstance(method, basestring): + if isinstance(method, string_types): method_name = method method = frappe.get_attr(method) else: @@ -151,7 +152,7 @@ def get_queue_list(queue_list=None): '''Defines possible queues. Also wraps a given queue in a list after validating.''' default_queue_list = queue_timeout.keys() if queue_list: - if isinstance(queue_list, basestring): + if isinstance(queue_list, string_types): queue_list = [queue_list] for queue in queue_list: diff --git a/frappe/utils/csvutils.py b/frappe/utils/csvutils.py index 825a38c5d7..26394c28bb 100644 --- a/frappe/utils/csvutils.py +++ b/frappe/utils/csvutils.py @@ -6,7 +6,7 @@ import frappe from frappe import msgprint, _ import json import csv -from six import StringIO, text_type +from six import StringIO, text_type, string_types from frappe.utils import encode, cstr, cint, flt, comma_or def read_csv_content_from_uploaded_file(ignore_encoding=False): @@ -78,7 +78,7 @@ def read_csv_content(fcontent, ignore_encoding=False): @frappe.whitelist() def send_csv_to_client(args): - if isinstance(args, basestring): + if isinstance(args, string_types): args = json.loads(args) args = frappe._dict(args) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index a07cb61957..94fad5ed0d 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -14,7 +14,7 @@ from num2words import num2words from six.moves import html_parser as HTMLParser from six.moves.urllib.parse import quote from html2text import html2text -from six import iteritems, text_type +from six import iteritems, text_type, string_types DATE_FORMAT = "%Y-%m-%d" TIME_FORMAT = "%H:%M:%S.%f" @@ -63,7 +63,7 @@ def get_datetime(datetime_str=None): return parser.parse(datetime_str) def to_timedelta(time_str): - if isinstance(time_str, basestring): + if isinstance(time_str, string_types): t = parser.parse(time_str) return datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second, microseconds=t.microsecond) @@ -80,7 +80,7 @@ def add_to_date(date, years=0, months=0, days=0, hours=0, as_string=False, as_da if hours: as_datetime = True - if isinstance(date, basestring): + if isinstance(date, string_types): as_string = True if " " in date: as_datetime = True @@ -196,7 +196,7 @@ def get_time(time_str): return parser.parse(time_str).time() def get_datetime_str(datetime_obj): - if isinstance(datetime_obj, basestring): + if isinstance(datetime_obj, string_types): datetime_obj = get_datetime(datetime_obj) return datetime_obj.strftime(DATETIME_FORMAT) @@ -261,7 +261,7 @@ def has_common(l1, l2): def flt(s, precision=None): """Convert to float (ignore commas)""" - if isinstance(s, basestring): + if isinstance(s, string_types): s = s.replace(',','') try: @@ -522,7 +522,7 @@ def pretty_date(iso_datetime): if not iso_datetime: return '' import math - if isinstance(iso_datetime, basestring): + if isinstance(iso_datetime, string_types): iso_datetime = datetime.datetime.strptime(iso_datetime, DATETIME_FORMAT) now_dt = datetime.datetime.strptime(now(), DATETIME_FORMAT) dt_diff = now_dt - iso_datetime diff --git a/frappe/utils/dateutils.py b/frappe/utils/dateutils.py index a9b5818efa..79722aa159 100644 --- a/frappe/utils/dateutils.py +++ b/frappe/utils/dateutils.py @@ -6,6 +6,7 @@ import frappe import frappe.defaults import datetime from frappe.utils import get_datetime +from six import string_types # global values -- used for caching dateformats = { @@ -68,7 +69,7 @@ def get_user_date_format(): def datetime_in_user_format(date_time): if not date_time: return "" - if isinstance(date_time, basestring): + if isinstance(date_time, string_types): date_time = get_datetime(date_time) from frappe.utils import formatdate return formatdate(date_time.date()) + " " + date_time.strftime("%H:%M") diff --git a/frappe/utils/formatters.py b/frappe/utils/formatters.py index bf5a81e4f7..4753fce060 100644 --- a/frappe/utils/formatters.py +++ b/frappe/utils/formatters.py @@ -7,11 +7,12 @@ import datetime from frappe.utils import formatdate, fmt_money, flt, cstr, cint, format_datetime, format_time from frappe.model.meta import get_field_currency, get_field_precision import re +from six import string_types def format_value(value, df=None, doc=None, currency=None, translated=False): '''Format value based on given fieldtype, document reference, currency reference. If docfield info (df) is not given, it will try and guess based on the datatype of the value''' - if isinstance(df, basestring): + if isinstance(df, string_types): df = frappe._dict(fieldtype=df) if not df: diff --git a/frappe/utils/html_utils.py b/frappe/utils/html_utils.py index 9824a64106..94c2563424 100644 --- a/frappe/utils/html_utils.py +++ b/frappe/utils/html_utils.py @@ -1,5 +1,6 @@ import json import bleach, bleach_whitelist +from six import string_types def sanitize_html(html, linkify=False): """ @@ -8,7 +9,7 @@ def sanitize_html(html, linkify=False): Does not sanitize JSON, as it could lead to future problems """ - if not isinstance(html, basestring): + if not isinstance(html, string_types): return html elif is_json(html): diff --git a/frappe/utils/make_random.py b/frappe/utils/make_random.py index e3ea5ba5b9..4b2f7688a5 100644 --- a/frappe/utils/make_random.py +++ b/frappe/utils/make_random.py @@ -1,5 +1,6 @@ import frappe, random from six.moves import range +from six import string_types settings = frappe._dict( prob = { @@ -15,7 +16,7 @@ def add_random_children(doc, fieldname, rows, randomize, unique=None): for i in range(nrows): d = {} for key, val in randomize.items(): - if isinstance(val[0], basestring): + if isinstance(val[0], string_types): d[key] = get_random(*val) else: d[key] = random.randrange(*val) diff --git a/frappe/utils/oauth.py b/frappe/utils/oauth.py index 8770ff56e9..61498a9722 100644 --- a/frappe/utils/oauth.py +++ b/frappe/utils/oauth.py @@ -6,6 +6,7 @@ import frappe import frappe.utils import json from frappe import _ +from six import string_types class SignupDisabledError(frappe.PermissionError): pass @@ -211,10 +212,10 @@ def login_oauth_user(data=None, provider=None, state=None, email_id=None, key=No # return # json.loads data and state - if isinstance(data, basestring): + if isinstance(data, string_types): data = json.loads(data) - if isinstance(state, basestring): + if isinstance(state, string_types): state = json.loads(state) if not (state and state["token"]): diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index 211bef028c..aaddc1958e 100755 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -23,6 +23,7 @@ from frappe.limits import has_expired from frappe.utils.data import get_datetime, now_datetime from frappe.core.doctype.user.user import STANDARD_USERS from frappe.installer import update_site_config +from six import string_types DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' @@ -192,7 +193,7 @@ def get_enabled_scheduler_events(): enabled_events = frappe.db.get_global("enabled_scheduler_events") if enabled_events: - if isinstance(enabled_events, basestring): + if isinstance(enabled_events, string_types): enabled_events = json.loads(enabled_events) return enabled_events diff --git a/frappe/utils/verified_command.py b/frappe/utils/verified_command.py index 57170295f8..c92f1a8e1a 100644 --- a/frappe/utils/verified_command.py +++ b/frappe/utils/verified_command.py @@ -8,12 +8,13 @@ from frappe import _ import frappe import frappe.utils +from six import string_types def get_signed_params(params): """Sign a url by appending `&_signature=xxxxx` to given params (string or dict). :param params: String or dict of parameters.""" - if not isinstance(params, basestring): + if not isinstance(params, string_types): params = urllib.urlencode(params) signature = hmac.new(params) diff --git a/frappe/utils/xlsxutils.py b/frappe/utils/xlsxutils.py index e41888a6cb..afd67cacaa 100644 --- a/frappe/utils/xlsxutils.py +++ b/frappe/utils/xlsxutils.py @@ -8,7 +8,7 @@ from frappe.utils import encode, cstr, cint, flt, comma_or import openpyxl from openpyxl.styles import Font from openpyxl import load_workbook -from six import StringIO +from six import StringIO, string_types # return xlsx file object @@ -23,7 +23,7 @@ def make_xlsx(data, sheet_name): for row in data: clean_row = [] for item in row: - if isinstance(item, basestring) and sheet_name != "Data Import Template": + if isinstance(item, string_types) and sheet_name != "Data Import Template": value = handle_html(item) else: value = item diff --git a/frappe/www/printview.py b/frappe/www/printview.py index 03782b9317..1ed4ee3782 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -10,6 +10,7 @@ from frappe.modules import get_doc_path from jinja2 import TemplateNotFound from frappe.utils import cint, strip_html from markdown2 import markdown +from six import string_types no_cache = 1 no_sitemap = 1 @@ -64,7 +65,7 @@ def get_html(doc, name=None, print_format=None, meta=None, print_settings = frappe.db.get_singles_dict("Print Settings") - if isinstance(no_letterhead, basestring): + if isinstance(no_letterhead, string_types): no_letterhead = cint(no_letterhead) elif no_letterhead is None: @@ -175,10 +176,10 @@ def get_html_and_style(doc, name=None, print_format=None, meta=None, no_letterhead=None, trigger_print=False): """Returns `html` and `style` of print format, used in PDF etc""" - if isinstance(doc, basestring) and isinstance(name, basestring): + if isinstance(doc, string_types) and isinstance(name, string_types): doc = frappe.get_doc(doc, name) - if isinstance(doc, basestring): + if isinstance(doc, string_types): doc = frappe.get_doc(json.loads(doc)) print_format = get_print_format_doc(print_format, meta=meta or frappe.get_meta(doc.doctype)) @@ -336,7 +337,7 @@ def has_value(df, doc): if value in (None, ""): return False - elif isinstance(value, basestring) and not strip_html(value).strip(): + elif isinstance(value, string_types) and not strip_html(value).strip(): return False elif isinstance(value, list) and not len(value): @@ -427,7 +428,7 @@ def column_has_value(data, fieldname): for row in data: value = row.get(fieldname) if value: - if isinstance(value, basestring): + if isinstance(value, string_types): if strip_html(value).strip(): has_value = True break From dfedd584ca8622da7fbc539fb76c7121944a4350 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 12:55:15 +0530 Subject: [PATCH 08/13] Explicitly convert dict.values() to list --- frappe/model/base_document.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 0151feac8e..5ba5ceea6f 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -296,7 +296,7 @@ class BaseDocument(object): doctype = self.doctype, columns = ", ".join(["`"+c+"`" for c in columns]), values = ", ".join(["%s"] * len(columns)) - ), d.values()) + ), list(d.values())) except Exception as e: if e.args[0]==1062: if "PRIMARY" in cstr(e.args[1]): @@ -338,7 +338,7 @@ class BaseDocument(object): set {values} where name=%s""".format( doctype = self.doctype, values = ", ".join(["`"+c+"`=%s" for c in columns]) - ), d.values() + [name]) + ), list(d.values()) + [name]) except Exception as e: if e.args[0]==1062 and "Duplicate" in cstr(e.args[1]): self.show_unique_validation_message(e) From 39af5d1f1cb7a11fb57d5bd460cdad4a69bdb854 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 15:16:10 +0530 Subject: [PATCH 09/13] Convert method name to string instead of encoding --- frappe/model/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 3e8db22802..e46b36880d 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -662,7 +662,7 @@ class Document(BaseDocument): # hack! to run hooks even if method does not exist fn = lambda self, *args, **kwargs: None - fn.__name__ = method.encode("utf-8") + fn.__name__ = str(method) out = Document.hook(fn)(self, *args, **kwargs) self.run_email_alerts(method) From 69c255661df6678d1f16ca5f492b16a135c07c50 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 15:50:26 +0530 Subject: [PATCH 10/13] Replaced long with six.integer_types --- frappe/database.py | 8 ++++---- frappe/utils/data.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frappe/database.py b/frappe/database.py index b702a8c53d..00f54491d1 100644 --- a/frappe/database.py +++ b/frappe/database.py @@ -18,7 +18,7 @@ import redis import frappe.model.meta from frappe.utils import now, get_datetime, cstr from frappe import _ -from six import text_type, binary_type +from six import text_type, binary_type, integer_types from frappe.utils.global_search import sync_global_search from frappe.model.utils.link_count import flush_local_link_count from six import iteritems, text_type @@ -270,7 +270,7 @@ class Database: """Returns true if the first row in the result has a Date, Datetime, Long Int.""" if result and result[0]: for v in result[0]: - if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, long)): + if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, integer_types)): return True if formatted and isinstance(v, (int, float)): return True @@ -287,7 +287,7 @@ class Database: from frappe.utils import formatdate, fmt_money - if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, long)): + if isinstance(v, (datetime.date, datetime.timedelta, datetime.datetime, integer_types)): if isinstance(v, datetime.date): v = text_type(v) if formatted: @@ -298,7 +298,7 @@ class Database: v = text_type(v) # long - elif isinstance(v, long): + elif isinstance(v, integer_types): v=int(v) # convert to strings... (if formatted) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index a07cb61957..e01a8b7bc2 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -14,7 +14,7 @@ from num2words import num2words from six.moves import html_parser as HTMLParser from six.moves.urllib.parse import quote from html2text import html2text -from six import iteritems, text_type +from six import iteritems, text_type, integer_types DATE_FORMAT = "%Y-%m-%d" TIME_FORMAT = "%H:%M:%S.%f" @@ -346,7 +346,7 @@ def parse_val(v): v = text_type(v) elif isinstance(v, datetime.timedelta): v = ":".join(text_type(v).split(":")[:2]) - elif isinstance(v, long): + elif isinstance(v, integer_types): v = int(v) return v From 5cc6903cd5107b3289ef2ce441568a618e967ddf Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 9 Aug 2017 16:11:24 +0530 Subject: [PATCH 11/13] Make sure that max_length[0][0] is comparable with new_length --- frappe/model/db_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/db_schema.py b/frappe/model/db_schema.py index 37d644883e..e47c678e4c 100644 --- a/frappe/model/db_schema.py +++ b/frappe/model/db_schema.py @@ -127,7 +127,7 @@ class DbTable: else: raise - if max_length and max_length[0][0] > new_length: + 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: From 2403a800c0eccae1b1ed1ca1de441bf28e6bac81 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Fri, 11 Aug 2017 12:56:59 +0530 Subject: [PATCH 12/13] Use absolute import for frappe.twofactor (#3915) --- frappe/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/auth.py b/frappe/auth.py index bd510b9fcd..b92e7e604d 100644 --- a/frappe/auth.py +++ b/frappe/auth.py @@ -17,7 +17,7 @@ from frappe.translate import get_lang_code from frappe.utils.password import check_password from frappe.core.doctype.authentication_log.authentication_log import add_authentication_log from frappe.utils.background_jobs import enqueue -from twofactor import (should_run_2fa, authenticate_for_2factor, +from frappe.twofactor import (should_run_2fa, authenticate_for_2factor, confirm_otp_token, get_cached_user_pass) from six.moves.urllib.parse import quote From 7397b6829031879119da34c31890a0f3f1569471 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 11 Aug 2017 13:00:10 +0530 Subject: [PATCH 13/13] Scrub urls fix (#3918) * Don't expand mailto urls * Add test case --- frappe/tests/test_utils.py | 30 ++++++++++++++++++++++++++++-- frappe/utils/data.py | 8 +++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/frappe/tests/test_utils.py b/frappe/tests/test_utils.py index af13829e7e..948e26a74f 100644 --- a/frappe/tests/test_utils.py +++ b/frappe/tests/test_utils.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import unittest -from frappe.utils import evaluate_filters, money_in_words +from frappe.utils import evaluate_filters, money_in_words, scrub_urls, get_url class TestFilters(unittest.TestCase): def test_simple_dict(self): @@ -57,4 +57,30 @@ class TestMoney(unittest.TestCase): self.assertEqual( money_in_words(num[0], "NGN"), num[1], "{0} is not the same as {1}". format(money_in_words(num[0], "NGN"), num[1]) - ) \ No newline at end of file + ) + +class TestDataManipulation(unittest.TestCase): + def test_scrub_urls(self): + html = ''' +

You have a new message from: John

+

Hey, wassup!

+ +
+ Please mail us at email +
+ ''' + + html = scrub_urls(html) + url = get_url() + + self.assertTrue('Test link 1' in html) + self.assertTrue('Test link 2'.format(url) in html) + self.assertTrue('Test link 3'.format(url) in html) + self.assertTrue(''.format(url) in html) + self.assertTrue('style="background-image: url(\'{0}/assets/frappe/bg.jpg\') !important"'.format(url) in html) + self.assertTrue('email' in html) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 8408b4f5aa..8de7e3266f 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -778,9 +778,11 @@ def expand_relative_urls(html): def _expand_relative_urls(match): to_expand = list(match.groups()) - if not to_expand[2].startswith("/"): - to_expand[2] = "/" + to_expand[2] - to_expand.insert(2, url) + + if not to_expand[2].startswith('mailto'): + if not to_expand[2].startswith("/"): + to_expand[2] = "/" + to_expand[2] + to_expand.insert(2, url) if 'url' in to_expand[0] and to_expand[1].startswith('(') and to_expand[-1].endswith(')'): # background-image: url('/assets/...') - workaround for wkhtmltopdf print-media-type