You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

357 lines
8.5 KiB

  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. # util __init__.py
  4. from __future__ import unicode_literals
  5. from werkzeug.test import Client
  6. import os, sys, re, urllib
  7. import frappe
  8. # utility functions like cint, int, flt, etc.
  9. from frappe.utils.data import *
  10. default_fields = ['doctype', 'name', 'owner', 'creation', 'modified', 'modified_by',
  11. 'parent', 'parentfield', 'parenttype', 'idx', 'docstatus']
  12. # used in import_docs.py
  13. # TODO: deprecate it
  14. def getCSVelement(v):
  15. """
  16. Returns the CSV value of `v`, For example:
  17. * apple becomes "apple"
  18. * hi"there becomes "hi""there"
  19. """
  20. v = cstr(v)
  21. if not v: return ''
  22. if (',' in v) or ('\n' in v) or ('"' in v):
  23. if '"' in v: v = v.replace('"', '""')
  24. return '"'+v+'"'
  25. else: return v or ''
  26. def get_fullname(user):
  27. """get the full name (first name + last name) of the user from User"""
  28. if not hasattr(frappe.local, "fullnames"):
  29. frappe.local.fullnames = {}
  30. if not frappe.local.fullnames.get(user):
  31. p = frappe.db.get_value("User", user, ["first_name", "last_name"], as_dict=True)
  32. if p:
  33. frappe.local.fullnames[user] = " ".join(filter(None,
  34. [p.get('first_name'), p.get('last_name')])) or user
  35. else:
  36. frappe.local.fullnames[user] = user
  37. return frappe.local.fullnames.get(user)
  38. def get_formatted_email(user):
  39. """get email id of user formatted as: John Doe <johndoe@example.com>"""
  40. if user == "Administrator":
  41. return user
  42. from email.utils import formataddr
  43. fullname = get_fullname(user)
  44. return formataddr((fullname, user))
  45. def extract_email_id(email):
  46. """fetch only the email part of the email id"""
  47. from email.utils import parseaddr
  48. fullname, email_id = parseaddr(email)
  49. if isinstance(email_id, basestring) and not isinstance(email_id, unicode):
  50. email_id = email_id.decode("utf-8", "ignore")
  51. return email_id
  52. def validate_email_add(email_str):
  53. """Validates the email string"""
  54. email = extract_email_id(email_str)
  55. match = re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", email.lower())
  56. if not match:
  57. return False
  58. return match.group(0)==email.lower()
  59. def random_string(length):
  60. """generate a random string"""
  61. import string
  62. from random import choice
  63. return ''.join([choice(string.letters + string.digits) for i in range(length)])
  64. def get_gravatar(email):
  65. import md5
  66. return "https://secure.gravatar.com/avatar/{hash}?d=retro".format(hash=md5.md5(email).hexdigest())
  67. def get_traceback():
  68. """
  69. Returns the traceback of the Exception
  70. """
  71. import traceback
  72. exc_type, value, tb = sys.exc_info()
  73. trace_list = traceback.format_tb(tb, None) + \
  74. traceback.format_exception_only(exc_type, value)
  75. body = "Traceback (innermost last):\n" + "%-20s %s" % \
  76. (unicode((b"").join(trace_list[:-1]), 'utf-8'), unicode(trace_list[-1], 'utf-8'))
  77. if frappe.logger:
  78. frappe.logger.error('Db:'+(frappe.db and frappe.db.cur_db_name or '') \
  79. + ' - ' + body)
  80. return body
  81. def log(event, details):
  82. frappe.logger.info(details)
  83. def dict_to_str(args, sep='&'):
  84. """
  85. Converts a dictionary to URL
  86. """
  87. t = []
  88. for k in args.keys():
  89. t.append(str(k)+'='+urllib.quote(str(args[k] or '')))
  90. return sep.join(t)
  91. # Get Defaults
  92. # ==============================================================================
  93. def get_defaults(key=None):
  94. """
  95. Get dictionary of default values from the defaults, or a value if key is passed
  96. """
  97. return frappe.db.get_defaults(key)
  98. def set_default(key, val):
  99. """
  100. Set / add a default value to defaults`
  101. """
  102. return frappe.db.set_default(key, val)
  103. def remove_blanks(d):
  104. """
  105. Returns d with empty ('' or None) values stripped
  106. """
  107. empty_keys = []
  108. for key in d:
  109. if d[key]=='' or d[key]==None:
  110. # del d[key] raises runtime exception, using a workaround
  111. empty_keys.append(key)
  112. for key in empty_keys:
  113. del d[key]
  114. return d
  115. def pprint_dict(d, level=1, no_blanks=True):
  116. """
  117. Pretty print a dictionary with indents
  118. """
  119. if no_blanks:
  120. remove_blanks(d)
  121. # make indent
  122. indent, ret = '', ''
  123. for i in range(0,level): indent += '\t'
  124. # add lines
  125. comment, lines = '', []
  126. kl = d.keys()
  127. kl.sort()
  128. # make lines
  129. for key in kl:
  130. if key != '##comment':
  131. tmp = {key: d[key]}
  132. lines.append(indent + str(tmp)[1:-1] )
  133. # add comment string
  134. if '##comment' in kl:
  135. ret = ('\n' + indent) + '# ' + d['##comment'] + '\n'
  136. # open
  137. ret += indent + '{\n'
  138. # lines
  139. ret += indent + ',\n\t'.join(lines)
  140. # close
  141. ret += '\n' + indent + '}'
  142. return ret
  143. def get_common(d1,d2):
  144. """
  145. returns (list of keys) the common part of two dicts
  146. """
  147. return [p for p in d1 if p in d2 and d1[p]==d2[p]]
  148. def get_common_dict(d1, d2):
  149. """
  150. return common dictionary of d1 and d2
  151. """
  152. ret = {}
  153. for key in d1:
  154. if key in d2 and d2[key]==d1[key]:
  155. ret[key] = d1[key]
  156. return ret
  157. def get_diff_dict(d1, d2):
  158. """
  159. return common dictionary of d1 and d2
  160. """
  161. diff_keys = set(d2.keys()).difference(set(d1.keys()))
  162. ret = {}
  163. for d in diff_keys: ret[d] = d2[d]
  164. return ret
  165. def get_file_timestamp(fn):
  166. """
  167. Returns timestamp of the given file
  168. """
  169. from frappe.utils import cint
  170. try:
  171. return str(cint(os.stat(fn).st_mtime))
  172. except OSError, e:
  173. if e.args[0]!=2:
  174. raise
  175. else:
  176. return None
  177. # to be deprecated
  178. def make_esc(esc_chars):
  179. """
  180. Function generator for Escaping special characters
  181. """
  182. return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
  183. # esc / unescape characters -- used for command line
  184. def esc(s, esc_chars):
  185. """
  186. Escape special characters
  187. """
  188. if not s:
  189. return ""
  190. for c in esc_chars:
  191. esc_str = '\\' + c
  192. s = s.replace(c, esc_str)
  193. return s
  194. def unesc(s, esc_chars):
  195. """
  196. UnEscape special characters
  197. """
  198. for c in esc_chars:
  199. esc_str = '\\' + c
  200. s = s.replace(esc_str, c)
  201. return s
  202. def execute_in_shell(cmd, verbose=0):
  203. # using Popen instead of os.system - as recommended by python docs
  204. from subprocess import Popen
  205. import tempfile
  206. with tempfile.TemporaryFile() as stdout:
  207. with tempfile.TemporaryFile() as stderr:
  208. p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
  209. p.wait()
  210. stdout.seek(0)
  211. out = stdout.read()
  212. stderr.seek(0)
  213. err = stderr.read()
  214. if verbose:
  215. if err: print err
  216. if out: print out
  217. return err, out
  218. def get_path(*path, **kwargs):
  219. base = kwargs.get('base')
  220. if not base:
  221. base = frappe.local.site_path
  222. return os.path.join(base, *path)
  223. def get_site_base_path(sites_dir=None, hostname=None):
  224. return frappe.local.site_path
  225. def get_site_path(*path):
  226. return get_path(base=get_site_base_path(), *path)
  227. def get_files_path(*path):
  228. return get_site_path("public", "files", *path)
  229. def get_backups_path():
  230. return get_site_path("private", "backups")
  231. def get_request_site_address(full_address=False):
  232. return get_url(full_address=full_address)
  233. def encode_dict(d, encoding="utf-8"):
  234. for key in d:
  235. if isinstance(d[key], basestring) and isinstance(d[key], unicode):
  236. d[key] = d[key].encode(encoding)
  237. return d
  238. def decode_dict(d, encoding="utf-8"):
  239. for key in d:
  240. if isinstance(d[key], basestring) and not isinstance(d[key], unicode):
  241. d[key] = d[key].decode(encoding, "ignore")
  242. return d
  243. def get_site_name(hostname):
  244. return hostname.split(':')[0]
  245. def get_disk_usage():
  246. """get disk usage of files folder"""
  247. files_path = get_files_path()
  248. if not os.path.exists(files_path):
  249. return 0
  250. err, out = execute_in_shell("du -hsm {files_path}".format(files_path=files_path))
  251. return cint(out.split("\n")[-2].split("\t")[0])
  252. def touch_file(path):
  253. with open(path, 'a'):
  254. os.utime(path, None)
  255. return True
  256. def get_test_client():
  257. from frappe.app import application
  258. return Client(application)
  259. def get_hook_method(hook_name, fallback=None):
  260. method = (frappe.get_hooks().get(hook_name))
  261. if method:
  262. method = frappe.get_attr(method[0])
  263. return method
  264. if fallback:
  265. return fallback
  266. def update_progress_bar(txt, i, l):
  267. lt = len(txt)
  268. if lt < 36:
  269. txt = txt + " "*(36-lt)
  270. complete = int(float(i+1) / l * 40)
  271. sys.stdout.write("\r{0}: [{1}{2}]".format(txt, "="*complete, " "*(40-complete)))
  272. sys.stdout.flush()
  273. def get_html_format(print_path):
  274. html_format = None
  275. if os.path.exists(print_path):
  276. with open(print_path, "r") as f:
  277. html_format = f.read()
  278. for include_directive, path in re.findall("""({% include ['"]([^'"]*)['"] %})""", html_format):
  279. for app_name in frappe.get_installed_apps():
  280. include_path = frappe.get_app_path(app_name, *path.split(os.path.sep))
  281. if os.path.exists(include_path):
  282. with open(include_path, "r") as f:
  283. html_format = html_format.replace(include_directive, f.read())
  284. break
  285. return html_format