diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index da9d67be3b..3610393d9a 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -443,7 +443,7 @@ def console(context): for app in all_apps: locals()[app] = __import__(app) print("Apps in this namespace:\n{}".format(", ".join(all_apps))) - IPython.embed(display_banner="", header="") + IPython.embed(display_banner="", header="", colors="neutral") @click.command('run-tests') diff --git a/frappe/desk/doctype/number_card/number_card.json b/frappe/desk/doctype/number_card/number_card.json index 5fb058d8ce..ec6a1e9190 100644 --- a/frappe/desk/doctype/number_card/number_card.json +++ b/frappe/desk/doctype/number_card/number_card.json @@ -1,6 +1,5 @@ { "actions": [], - "autoname": "CARD.#####", "creation": "2020-04-15 18:06:39.444683", "doctype": "DocType", "editable_grid": 1, @@ -99,7 +98,7 @@ } ], "links": [], - "modified": "2020-05-01 15:23:29.550243", + "modified": "2020-05-06 19:47:57.753574", "modified_by": "Administrator", "module": "Desk", "name": "Number Card", diff --git a/frappe/desk/doctype/number_card/number_card.py b/frappe/desk/doctype/number_card/number_card.py index 2c5655beda..64f517bffc 100644 --- a/frappe/desk/doctype/number_card/number_card.py +++ b/frappe/desk/doctype/number_card/number_card.py @@ -6,10 +6,15 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document from frappe.utils import cint +from frappe.model.naming import append_number_if_name_exists class NumberCard(Document): - pass + def autoname(self): + if not self.name: + self.name = self.label + if frappe.db.exists("Number Card", self.name): + self.name = append_number_if_name_exists('Number Card', self.name) def get_permission_query_conditions(user=None): if not user: diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index 164f6389eb..74e841f107 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -299,7 +299,6 @@ def export_query(): _("You can try changing the filters of your report.")) return - data.columns = [col for col in data.columns if isinstance(col, dict) and not col.get('hidden')] columns = get_columns_dict(data.columns) from frappe.utils.xlsxutils import make_xlsx @@ -316,7 +315,8 @@ def build_xlsx_data(columns, data, visible_idx, include_indentation): # add column headings for idx in range(len(data.columns)): - result[0].append(columns[idx]["label"]) + if not columns[idx].get("hidden"): + result[0].append(columns[idx]["label"]) # build table from result for i, row in enumerate(data.result): diff --git a/frappe/integrations/offsite_backup_utils.py b/frappe/integrations/offsite_backup_utils.py index c280a1d9dd..7e80cb68c4 100644 --- a/frappe/integrations/offsite_backup_utils.py +++ b/frappe/integrations/offsite_backup_utils.py @@ -10,7 +10,7 @@ from frappe.utils import split_emails, get_backups_path def send_email(success, service_name, doctype, email_field, error_status=None): - recipients = get_recipients(service_name, email_field) + recipients = get_recipients(doctype, email_field) if not recipients: frappe.log_error("No Email Recipient found for {0}".format(service_name), "{0}: Failed to send backup status email".format(service_name)) @@ -36,11 +36,11 @@ def send_email(success, service_name, doctype, email_field, error_status=None): frappe.sendmail(recipients=recipients, subject=subject, message=message) -def get_recipients(service_name, email_field): +def get_recipients(doctype, email_field): if not frappe.db: frappe.connect() - return split_emails(frappe.db.get_value(service_name, None, email_field)) + return split_emails(frappe.db.get_value(doctype, None, email_field)) def get_latest_backup_file(with_files=False): diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 2321e0c22a..7bf93d1968 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -452,10 +452,11 @@ class Meta(Document): for link in self.links: link.added = False for group in data.transactions: + group = frappe._dict(group) # group found - if group.label == link.label: - if not link.link_doctype in group.items: - group.items.append(link.link_doctype) + if link.group and group.label == link.group: + if link.link_doctype not in group.get('items'): + group.get('items').append(link.link_doctype) link.added = True if not link.added: diff --git a/frappe/public/js/frappe/recorder/RequestDetail.vue b/frappe/public/js/frappe/recorder/RequestDetail.vue index 804c1c2f55..60795076ec 100644 --- a/frappe/public/js/frappe/recorder/RequestDetail.vue +++ b/frappe/public/js/frappe/recorder/RequestDetail.vue @@ -126,27 +126,9 @@ @@ -244,7 +226,6 @@ export default { }, group_duplicates: false, showing: null, - showing_traceback: null, request: { calls: [], }, diff --git a/frappe/recorder.py b/frappe/recorder.py index ffafffb93f..388efcbf6e 100644 --- a/frappe/recorder.py +++ b/frappe/recorder.py @@ -9,12 +9,8 @@ import inspect import json import re import time -import traceback import frappe import sqlparse -from pygments import highlight -from pygments.lexers import PythonLexer -from pygments.formatters import HtmlFormatter from frappe import _ @@ -30,7 +26,7 @@ def sql(*args, **kwargs): stack = list(get_current_stack_frames()) - if frappe.db.db_type == 'postgres': + if frappe.db.db_type == "postgres": query = frappe.db._cursor.query else: query = frappe.db._cursor._executed @@ -65,9 +61,6 @@ def get_current_stack_frames(): "filename": re.sub(".*/apps/", "", filename), "lineno": lineno, "function": function, - "context": "".join(context), - "index": index, - "locals": json.dumps(frame.f_locals, skipkeys=True, default=str) } @@ -83,7 +76,7 @@ def dump(): frappe.local._recorder.dump() -class Recorder(): +class Recorder: def __init__(self): self.uuid = frappe.generate_hash(length=10) self.time = datetime.datetime.now() @@ -105,12 +98,18 @@ class Recorder(): "cmd": self.cmd, "time": self.time, "queries": len(self.calls), - "time_queries": float("{:0.3f}".format(sum(call["duration"] for call in self.calls))), - "duration": float("{:0.3f}".format((datetime.datetime.now() - self.time).total_seconds() * 1000)), + "time_queries": float( + "{:0.3f}".format(sum(call["duration"] for call in self.calls)) + ), + "duration": float( + "{:0.3f}".format((datetime.datetime.now() - self.time).total_seconds() * 1000) + ), "method": self.method, } frappe.cache().hset(RECORDER_REQUEST_SPARSE_HASH, self.uuid, request_data) - frappe.publish_realtime(event="recorder-dump-event", message=json.dumps(request_data, default=str)) + frappe.publish_realtime( + event="recorder-dump-event", message=json.dumps(request_data, default=str) + ) self.mark_duplicates() @@ -137,6 +136,7 @@ def do_not_record(function): del frappe.local._recorder frappe.db.sql = frappe.db._sql return function(*args, **kwargs) + return wrapper @@ -145,6 +145,7 @@ def administrator_only(function): if frappe.session.user != "Administrator": frappe.throw(_("Only Administrator is allowed to use Recorder")) return function(*args, **kwargs) + return wrapper @@ -175,11 +176,6 @@ def stop(*args, **kwargs): def get(uuid=None, *args, **kwargs): if uuid: result = frappe.cache().hget(RECORDER_REQUEST_HASH, uuid) - lexer = PythonLexer(tabsize=4) - for call in result["calls"]: - for stack in call["stack"]: - formatter = HtmlFormatter(noclasses=True, hl_lines=[stack["index"] + 1]) - stack["context"] = highlight(stack["context"], lexer, formatter) else: result = list(frappe.cache().hgetall(RECORDER_REQUEST_SPARSE_HASH).values()) return result diff --git a/frappe/templates/base.html b/frappe/templates/base.html index 907a7b6113..dd5dd63a1f 100644 --- a/frappe/templates/base.html +++ b/frappe/templates/base.html @@ -65,7 +65,7 @@ frappe.ready_events.push(fn); } window.dev_server = {{ dev_server }}; - window.socketio_port = {{ frappe.socketio_port }}; + window.socketio_port = {{ (frappe.socketio_port or 'null') }}; diff --git a/frappe/utils/dashboard.py b/frappe/utils/dashboard.py index 7cc97ed3f9..bb835d6561 100644 --- a/frappe/utils/dashboard.py +++ b/frappe/utils/dashboard.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from functools import wraps -from frappe.utils import add_to_date, get_link_to_form +from frappe.utils import add_to_date, cint, get_link_to_form from frappe.modules.import_file import import_doc @@ -75,6 +75,8 @@ def get_from_date_from_timespan(to_date, timespan): def sync_dashboards(app=None): """Import, overwrite fixtures from `[app]/fixtures`""" + if not cint(frappe.db.get_single_value('System Settings', 'setup_complete')): + return if app: apps = [app] else: diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 9ee683b12f..58c74a905d 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -22,6 +22,11 @@ DATE_FORMAT = "%Y-%m-%d" TIME_FORMAT = "%H:%M:%S.%f" DATETIME_FORMAT = DATE_FORMAT + " " + TIME_FORMAT + +def is_invalid_date_string(date_string): + # dateutil parser does not agree with dates like "0001-01-01" or "0000-00-00" + return (not date_string) or (date_string or "").startswith(("0001-01-01", "0000-00-00")) + # datetime functions def getdate(string_date=None): """ @@ -36,9 +41,9 @@ def getdate(string_date=None): elif isinstance(string_date, datetime.date): return string_date - # dateutil parser does not agree with dates like 0001-01-01 - if not string_date or string_date=="0001-01-01": + if is_invalid_date_string(string_date): return None + return parser.parse(string_date).date() def get_datetime(datetime_str=None): @@ -54,8 +59,7 @@ def get_datetime(datetime_str=None): elif isinstance(datetime_str, datetime.date): return datetime.datetime.combine(datetime_str, datetime.time()) - # dateutil parser does not agree with dates like "0001-01-01" or "0000-00-00" - if not datetime_str or (datetime_str or "").startswith(("0001-01-01", "0000-00-00")): + if is_invalid_date_string(datetime_str): return None try: diff --git a/requirements.txt b/requirements.txt index 6c22d66139..f05e0f3870 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,10 +23,10 @@ googlemaps==3.1.1 gunicorn==19.10.0 html2text==2016.9.19 html5lib==1.0.1 -ipython==5.9.0 +ipython==7.14.0 Jinja2==2.11.1 ldap3==2.7 -markdown2==2.3.8 +markdown2==2.3.9 maxminddb-geolite2==2018.703 ndg-httpsclient==0.5.1 num2words==0.5.5 @@ -38,7 +38,6 @@ Pillow==6.2.2 premailer==3.6.1 psycopg2-binary==2.8.4 pyasn1==0.4.8 -Pygments==2.5.2 PyJWT==1.7.1 PyMySQL==0.9.3 pyOpenSSL==19.1.0