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 @@
-
+
| {{ row[key] }} |
-
- |
-
-
-
-
-
- | Variable | Value |
-
-
-
- | {{ variable[0] }} |
- {{ variable[1] }} |
-
-
-
- |
-
@@ -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