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.

пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 14 година
пре 14 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 14 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 13 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 13 година
пре 14 година
пре 13 година
пре 13 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. #
  3. # MIT License (MIT)
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. # and/or sell copies of the Software, and to permit persons to whom the
  10. # Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #
  22. # util __init__.py
  23. from __future__ import unicode_literals
  24. import webnotes
  25. user_time_zone = None
  26. month_name = ['','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
  27. month_name_full = ['','January','February','March','April','May','June','July','August','September','October','November','December']
  28. no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable', 'Button', 'Image', 'Graph']
  29. default_fields = ['doctype','name','owner','creation','modified','modified_by','parent','parentfield','parenttype','idx','docstatus']
  30. def getCSVelement(v):
  31. """
  32. Returns the CSV value of `v`, For example:
  33. * apple becomes "apple"
  34. * hi"there becomes "hi""there"
  35. """
  36. v = cstr(v)
  37. if not v: return ''
  38. if (',' in v) or ('\n' in v) or ('"' in v):
  39. if '"' in v: v = v.replace('"', '""')
  40. return '"'+v+'"'
  41. else: return v or ''
  42. def get_fullname(profile):
  43. """get the full name (first name + last name) of the user from Profile"""
  44. p = webnotes.conn.sql("""select first_name, last_name from `tabProfile`
  45. where name=%s""", profile, as_dict=1)
  46. if p:
  47. p = p[0]
  48. full_name = (p['first_name'] and (p['first_name'] + ' ') or '') + (p['last_name'] or '')
  49. return full_name or profile
  50. else:
  51. return profile
  52. def decode_email_header(s):
  53. import email.header
  54. # replace double quotes with blank
  55. # double quotes in header prohibit decoding of header
  56. decoded_header_tuple = email.header.decode_header(s.replace('"', ''))
  57. decoded_list = map(lambda h: unicode(h[0], encoding=h[1] or 'utf-8'), decoded_header_tuple)
  58. return " ".join(decoded_list)
  59. def extract_email_id(s):
  60. """
  61. Extract email id from email header format
  62. """
  63. if '<' in s:
  64. s = s.split('<')[1].split('>')[0]
  65. if s:
  66. s = s.strip().lower()
  67. return s
  68. def get_email_id(user):
  69. """get email id of user formatted as: John Doe <johndoe@example.com>"""
  70. if user == "Administrator":
  71. return user
  72. fullname = get_fullname(user)
  73. return "%s <%s>" % (fullname, user)
  74. def validate_email_add(email_str):
  75. """Validates the email string"""
  76. s = extract_email_id(email_str)
  77. import re
  78. #return re.match("^[a-zA-Z0-9._%-]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email_str)
  79. return 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])?", s)
  80. def sendmail(recipients, sender='', msg='', subject='[No Subject]', parts=[], cc=[], attach=[]):
  81. """Send an email. For more details see :func:`email_lib.sendmail`"""
  82. import webnotes.utils.email_lib
  83. return email_lib.sendmail(recipients, sender, msg, subject, parts, cc, attach)
  84. def get_request_site_address():
  85. """get app url from request"""
  86. import os
  87. try:
  88. return 'HTTPS' in os.environ.get('SERVER_PROTOCOL') and 'https://' or 'http://' \
  89. + os.environ.get('HTTP_HOST')
  90. except TypeError, e:
  91. return 'http://localhost'
  92. def random_string(length):
  93. """generate a random string"""
  94. import string
  95. from random import choice
  96. return ''.join([choice(string.letters + string.digits) for i in range(length)])
  97. def db_exists(dt, dn):
  98. return webnotes.conn.sql('select name from `tab%s` where name="%s"' % (dt, dn))
  99. def load_json(arg):
  100. # already a dictionary?
  101. if not isinstance(arg, basestring):
  102. return arg
  103. import json
  104. return json.loads(arg, encoding='utf-8')
  105. # Get Traceback
  106. # ==============================================================================
  107. def getTraceback():
  108. """
  109. Returns the traceback of the Exception
  110. """
  111. import sys, traceback, string
  112. exc_type, value, tb = sys.exc_info()
  113. trace_list = traceback.format_tb(tb, None) + traceback.format_exception_only(exc_type, value)
  114. body = "Traceback (innermost last):\n" + "%-20s %s" % \
  115. (unicode((b"").join(trace_list[:-1]), 'utf-8'), unicode(trace_list[-1], 'utf-8'))
  116. if webnotes.logger:
  117. webnotes.logger.error('Db:'+(webnotes.conn and webnotes.conn.cur_db_name or '') + ' - ' + body)
  118. return body
  119. # Log
  120. # ==============================================================================
  121. def log(event, details):
  122. webnotes.logger.info(details)
  123. # Date and Time
  124. # ==============================================================================
  125. def getdate(string_date):
  126. """
  127. Coverts string date (yyyy-mm-dd) to datetime.date object
  128. """
  129. import datetime
  130. if type(string_date)==unicode:
  131. string_date = str(string_date)
  132. if type(string_date) in (datetime.datetime, datetime.date):
  133. return string_date
  134. if ' ' in string_date:
  135. string_date = string_date.split(' ')[0]
  136. t = string_date.split('-')
  137. if len(t)==3:
  138. return datetime.date(cint(t[0]), cint(t[1]), cint(t[2]))
  139. else:
  140. return ''
  141. def add_days(date, days, format='string'):
  142. """
  143. Adds `days` to the given `string_date`
  144. """
  145. import datetime
  146. if not date:
  147. date = now_datetime()
  148. if type(date) not in (datetime.datetime, datetime.date):
  149. date = getdate(date)
  150. dt = date + datetime.timedelta(days)
  151. if format=='string':
  152. return dt.strftime('%Y-%m-%d')
  153. else:
  154. return dt
  155. def add_months(string_date, months):
  156. import datetime
  157. return webnotes.conn.sql("select DATE_ADD('%s',INTERVAL '%s' MONTH)" % (getdate(string_date),months))[0][0]
  158. def add_years(string_date, years):
  159. import datetime
  160. return webnotes.conn.sql("select DATE_ADD('%s',INTERVAL '%s' YEAR)" % (getdate(string_date),years))[0][0]
  161. def date_diff(string_ed_date, string_st_date=None):
  162. import datetime
  163. return webnotes.conn.sql("SELECT DATEDIFF('%s','%s')" %(getdate(string_ed_date), getdate(string_st_date)))[0][0]
  164. def now_datetime():
  165. global user_time_zone
  166. from datetime import datetime
  167. from pytz import timezone
  168. # get localtime
  169. if not user_time_zone:
  170. user_time_zone = webnotes.conn.get_value('Control Panel', None, 'time_zone') \
  171. or 'Asia/Calcutta'
  172. # convert to UTC
  173. utcnow = timezone('UTC').localize(datetime.utcnow())
  174. # convert to user time zone
  175. return utcnow.astimezone(timezone(user_time_zone))
  176. def now():
  177. """return current datetime as yyyy-mm-dd hh:mm:ss"""
  178. return now_datetime().strftime('%Y-%m-%d %H:%M:%S')
  179. def nowdate():
  180. """return current date as yyyy-mm-dd"""
  181. return now_datetime().strftime('%Y-%m-%d')
  182. def nowtime():
  183. """return current time in hh:mm"""
  184. return now_datetime().strftime('%H:%M')
  185. def get_first_day(dt, d_years=0, d_months=0):
  186. """
  187. Returns the first day of the month for the date specified by date object
  188. Also adds `d_years` and `d_months` if specified
  189. """
  190. import datetime
  191. # d_years, d_months are "deltas" to apply to dt
  192. y, m = dt.year + d_years, dt.month + d_months
  193. a, m = divmod(m-1, 12)
  194. return datetime.date(y+a, m+1, 1)
  195. def get_last_day(dt):
  196. """
  197. Returns last day of the month using:
  198. `get_first_day(dt, 0, 1) + datetime.timedelta(-1)`
  199. """
  200. import datetime
  201. return get_first_day(dt, 0, 1) + datetime.timedelta(-1)
  202. user_format = None
  203. """
  204. User format specified in :term:`Control Panel`
  205. Examples:
  206. * dd-mm-yyyy
  207. * mm-dd-yyyy
  208. * dd/mm/yyyy
  209. """
  210. def formatdate(string_date=None):
  211. """
  212. Convers the given string date to :data:`user_format`
  213. """
  214. global user_format
  215. if not user_format:
  216. user_format = webnotes.conn.get_value('Control Panel', None, 'date_format')
  217. if not string_date:
  218. string_date = nowdate()
  219. if not isinstance(string_date, basestring):
  220. string_date = str(string_date)
  221. d = string_date.split('-');
  222. out = user_format
  223. return out.replace('dd', ('%.2i' % cint(d[2]))).replace('mm', ('%.2i' % cint(d[1]))).replace('yyyy', d[0])
  224. def dict_to_str(args, sep='&'):
  225. """
  226. Converts a dictionary to URL
  227. """
  228. import urllib
  229. t = []
  230. for k in args.keys():
  231. t.append(str(k)+'='+urllib.quote(str(args[k] or '')))
  232. return sep.join(t)
  233. def timestamps_equal(t1, t2):
  234. """Returns true if same the two string timestamps are same"""
  235. scrub = lambda x: x.replace(':', ' ').replace('-',' ').split()
  236. t1, t2 = scrub(t1), scrub(t2)
  237. if len(t1) != len(t2):
  238. return
  239. for i in range(len(t1)):
  240. if t1[i]!=t2[i]:
  241. return
  242. return 1
  243. def global_date_format(date):
  244. """returns date as 1 January 2012"""
  245. import datetime
  246. if isinstance(date, basestring):
  247. date = getdate(date)
  248. return cstr(cint(date.strftime('%d'))) + ' ' + month_name_full[int(date.strftime('%m'))] \
  249. + ' ' + date.strftime('%Y')
  250. # Datatype
  251. # ==============================================================================
  252. def isNull(v):
  253. """
  254. Returns true if v='' or v is `None`
  255. """
  256. return (v=='' or v==None)
  257. def has_common(l1, l2):
  258. """
  259. Returns true if there are common elements in lists l1 and l2
  260. """
  261. for l in l1:
  262. if l in l2:
  263. return 1
  264. return 0
  265. def flt(s):
  266. """
  267. Convert to float (ignore commas)
  268. """
  269. if isinstance(s, basestring): # if string
  270. s = s.replace(',','')
  271. try: tmp = float(s)
  272. except: tmp = 0
  273. return tmp
  274. def cint(s):
  275. """
  276. Convert to integer
  277. """
  278. try: tmp = int(float(s))
  279. except: tmp = 0
  280. return tmp
  281. def cstr(s):
  282. if isinstance(s, unicode):
  283. return s
  284. elif s==None:
  285. return ''
  286. elif isinstance(s, basestring):
  287. return unicode(s, 'utf-8')
  288. else:
  289. return unicode(s)
  290. def str_esc_quote(s):
  291. """
  292. Escape quotes
  293. """
  294. if s==None:return ''
  295. return s.replace("'","\'")
  296. def replace_newlines(s):
  297. """
  298. Replace newlines by '<br>'
  299. """
  300. if s==None:return ''
  301. return s.replace("\n","<br>")
  302. def encode(obj, encoding="utf-8"):
  303. if isinstance(obj, list):
  304. out = []
  305. for o in obj:
  306. if isinstance(o, unicode):
  307. out.append(o.encode(encoding))
  308. else:
  309. out.append(o)
  310. return out
  311. elif isinstance(obj, unicode):
  312. return obj.encode(encoding)
  313. else:
  314. return obj
  315. # ==============================================================================
  316. def parse_val(v):
  317. """
  318. Converts to simple datatypes from SQL query results
  319. """
  320. import datetime
  321. if type(v)==datetime.date:
  322. v = str(v)
  323. elif type(v)==datetime.timedelta:
  324. v = ':'.join(str(v).split(':')[:2])
  325. elif type(v)==datetime.datetime:
  326. v = str(v)
  327. elif type(v)==long: v=int(v)
  328. return v
  329. # ==============================================================================
  330. #
  331. # def fmt_money(amount, decimal_fmt="%02.d"):
  332. # """
  333. # Convert to string with commas for thousands, millions etc
  334. # """
  335. # currency_format = webnotes.conn.get_value('Control Panel', None, 'currency_format') \
  336. # or 'Millions'
  337. # comma_frequency = (currency_format == "Millions") and 3 or 2
  338. # minus = flt(amount) < 0 and "-" or ""
  339. #
  340. # # get whole and fraction parts
  341. # str_amount = cstr(amount)
  342. # if "." in str_amount:
  343. # amount_whole = abs(cint(str_amount.split(".")[0]))
  344. # amount_fraction = cint(str_amount.split(".")[1])
  345. # else:
  346. # amount_whole = abs(cint(str_amount))
  347. # amount_fraction = 0
  348. #
  349. # # reverse the whole part, so that it is easy to append commas
  350. # whole_reversed = cstr(amount_whole)[::-1]
  351. # whole_with_comma = whole_reversed[:3]
  352. # if len(whole_reversed) > 3:
  353. # remaining_str = whole_reversed[3:]
  354. # for i in xrange(len(remaining_str)):
  355. # # insert a comma after the specified frequency of digits
  356. # if i%comma_frequency==0:
  357. # whole_with_comma += ","
  358. # whole_with_comma += remaining_str[i]
  359. # # reverse the whole part again to get the original number back!
  360. # whole_with_comma = whole_with_comma[::-1]
  361. # webnotes.msgprint(decimal_fmt)
  362. # webnotes.msgprint(("%s%s."+decimal_fmt) % (minus, whole_with_comma, amount_fraction))
  363. # return ("%s%s."+decimal_fmt) % (minus, whole_with_comma, amount_fraction)
  364. def fmt_money(amount, precision=2):
  365. """
  366. Convert to string with commas for thousands, millions etc
  367. """
  368. curr = webnotes.conn.get_value('Control Panel', None, 'currency_format') or 'Millions'
  369. amount = '%.*f' % (precision, flt(amount))
  370. val = 2
  371. if curr == 'Millions': val = 3
  372. if amount.find('.') == -1: temp = '00'
  373. else: temp = amount.split('.')[1]
  374. l = []
  375. minus = ''
  376. if flt(amount) < 0: minus = '-'
  377. amount = ''.join(amount.split(','))
  378. amount = cstr(abs(flt(amount))).split('.')[0]
  379. # main logic
  380. if len(amount) > 3:
  381. nn = amount[len(amount)-3:]
  382. l.append(nn)
  383. amount = amount[0:len(amount)-3]
  384. while len(amount) > val:
  385. nn = amount[len(amount)-val:]
  386. l.insert(0,nn)
  387. amount = amount[0:len(amount)-val]
  388. if len(amount) > 0: l.insert(0,amount)
  389. amount = ','.join(l)+'.'+temp
  390. amount = minus + amount
  391. return amount
  392. #
  393. # convet currency to words
  394. #
  395. def money_in_words(number, main_currency = None, fraction_currency=None):
  396. """
  397. Returns string in words with currency and fraction currency.
  398. """
  399. d = get_defaults()
  400. if not main_currency:
  401. main_currency = d.get('currency', 'INR')
  402. if not fraction_currency:
  403. fraction_currency = d.get('fraction_currency', 'paise')
  404. n = "%.2f" % flt(number)
  405. main, fraction = n.split('.')
  406. if len(fraction)==1: fraction += '0'
  407. out = main_currency + ' ' + in_words(main).title()
  408. if cint(fraction):
  409. out = out + ' and ' + in_words(fraction).title() + ' ' + fraction_currency
  410. return out + ' only.'
  411. #
  412. # convert number to words
  413. #
  414. def in_words(integer):
  415. """
  416. Returns string in words for the given integer.
  417. """
  418. in_million = webnotes.conn.get_default('currency_format')=='Millions' and 1 or 0
  419. n=int(integer)
  420. known = {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten',
  421. 11: 'eleven', 12: 'twelve', 13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen', 18: 'eighteen',
  422. 19: 'nineteen', 20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty', 60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'}
  423. def psn(n, known, xpsn):
  424. import sys;
  425. if n in known: return known[n]
  426. bestguess, remainder = str(n), 0
  427. if n<=20:
  428. print >>sys.stderr, n, "How did this happen?"
  429. assert 0
  430. elif n < 100:
  431. bestguess= xpsn((n//10)*10, known, xpsn) + '-' + xpsn(n%10, known, xpsn)
  432. return bestguess
  433. elif n < 1000:
  434. bestguess= xpsn(n//100, known, xpsn) + ' ' + 'hundred'
  435. remainder = n%100
  436. else:
  437. if in_million:
  438. if n < 1000000:
  439. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  440. remainder = n%1000
  441. elif n < 1000000000:
  442. bestguess= xpsn(n//1000000, known, xpsn) + ' ' + 'million'
  443. remainder = n%1000000
  444. else:
  445. bestguess= xpsn(n//1000000000, known, xpsn) + ' ' + 'billion'
  446. remainder = n%1000000000
  447. else:
  448. if n < 100000:
  449. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  450. remainder = n%1000
  451. elif n < 10000000:
  452. bestguess= xpsn(n//100000, known, xpsn) + ' ' + 'lakh'
  453. remainder = n%100000
  454. else:
  455. bestguess= xpsn(n//10000000, known, xpsn) + ' ' + 'crore'
  456. remainder = n%10000000
  457. if remainder:
  458. if remainder >= 100:
  459. comma = ','
  460. else:
  461. comma = ''
  462. return bestguess + comma + ' ' + xpsn(remainder, known, xpsn)
  463. else:
  464. return bestguess
  465. return psn(n, known, psn)
  466. # Get Defaults
  467. # ==============================================================================
  468. def get_defaults(key=None):
  469. """
  470. Get dictionary of default values from the :term:`Control Panel`, or a value if key is passed
  471. """
  472. return webnotes.conn.get_defaults(key)
  473. def set_default(key, val):
  474. """
  475. Set / add a default value to :term:`Control Panel`
  476. """
  477. return webnotes.conn.set_default(key, val)
  478. #
  479. # Clear recycle bin
  480. #
  481. def clear_recycle_bin():
  482. sql = webnotes.conn.sql
  483. tl = sql('show tables')
  484. total_deleted = 0
  485. for t in tl:
  486. fl = [i[0] for i in sql('desc `%s`' % t[0])]
  487. if 'name' in fl:
  488. total_deleted += sql("select count(*) from `%s` where name like '__overwritten:%%'" % t[0])[0][0]
  489. sql("delete from `%s` where name like '__overwritten:%%'" % t[0])
  490. if 'parent' in fl:
  491. total_deleted += sql("select count(*) from `%s` where parent like '__oldparent:%%'" % t[0])[0][0]
  492. sql("delete from `%s` where parent like '__oldparent:%%'" % t[0])
  493. total_deleted += sql("select count(*) from `%s` where parent like 'oldparent:%%'" % t[0])[0][0]
  494. sql("delete from `%s` where parent like 'oldparent:%%'" % t[0])
  495. total_deleted += sql("select count(*) from `%s` where parent like 'old_parent:%%'" % t[0])[0][0]
  496. sql("delete from `%s` where parent like 'old_parent:%%'" % t[0])
  497. return "%s records deleted" % str(int(total_deleted))
  498. # Dictionary utils
  499. # ==============================================================================
  500. def remove_blanks(d):
  501. """
  502. Returns d with empty ('' or None) values stripped
  503. """
  504. empty_keys = []
  505. for key in d:
  506. if d[key]=='' or d[key]==None:
  507. # del d[key] raises runtime exception, using a workaround
  508. empty_keys.append(key)
  509. for key in empty_keys:
  510. del d[key]
  511. return d
  512. def pprint_dict(d, level=1, no_blanks=True):
  513. """
  514. Pretty print a dictionary with indents
  515. """
  516. if no_blanks:
  517. remove_blanks(d)
  518. # make indent
  519. indent, ret = '', ''
  520. for i in range(0,level): indent += '\t'
  521. # add lines
  522. comment, lines = '', []
  523. kl = d.keys()
  524. kl.sort()
  525. # make lines
  526. for key in kl:
  527. if key != '##comment':
  528. tmp = {key: d[key]}
  529. lines.append(indent + str(tmp)[1:-1] )
  530. # add comment string
  531. if '##comment' in kl:
  532. ret = ('\n' + indent) + '# ' + d['##comment'] + '\n'
  533. # open
  534. ret += indent + '{\n'
  535. # lines
  536. ret += indent + ',\n\t'.join(lines)
  537. # close
  538. ret += '\n' + indent + '}'
  539. return ret
  540. def get_common(d1,d2):
  541. """
  542. returns (list of keys) the common part of two dicts
  543. """
  544. return [p for p in d1 if p in d2 and d1[p]==d2[p]]
  545. def get_common_dict(d1, d2):
  546. """
  547. return common dictionary of d1 and d2
  548. """
  549. ret = {}
  550. for key in d1:
  551. if key in d2 and d2[key]==d1[key]:
  552. ret[key] = d1[key]
  553. return ret
  554. def get_diff_dict(d1, d2):
  555. """
  556. return common dictionary of d1 and d2
  557. """
  558. diff_keys = set(d2.keys()).difference(set(d1.keys()))
  559. ret = {}
  560. for d in diff_keys: ret[d] = d2[d]
  561. return ret
  562. def get_file_timestamp(fn):
  563. """
  564. Returns timestamp of the given file
  565. """
  566. import os
  567. from webnotes.utils import cint
  568. try:
  569. return str(cint(os.stat(fn).st_mtime))
  570. except OSError, e:
  571. if e.args[0]!=2:
  572. raise e
  573. else:
  574. return None
  575. # to be deprecated
  576. def make_esc(esc_chars):
  577. """
  578. Function generator for Escaping special characters
  579. """
  580. return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
  581. # esc / unescape characters -- used for command line
  582. def esc(s, esc_chars):
  583. """
  584. Escape special characters
  585. """
  586. for c in esc_chars:
  587. esc_str = '\\' + c
  588. s = s.replace(c, esc_str)
  589. return s
  590. def unesc(s, esc_chars):
  591. """
  592. UnEscape special characters
  593. """
  594. for c in esc_chars:
  595. esc_str = '\\' + c
  596. s = s.replace(esc_str, c)
  597. return s
  598. def strip_html(text):
  599. """
  600. removes anything enclosed in and including <>
  601. """
  602. import re
  603. return re.compile(r'<.*?>').sub('', text)
  604. def escape_html(text):
  605. html_escape_table = {
  606. "&": "&amp;",
  607. '"': "&quot;",
  608. "'": "&apos;",
  609. ">": "&gt;",
  610. "<": "&lt;",
  611. }
  612. return "".join(html_escape_table.get(c,c) for c in text)
  613. def get_doctype_label(dt=None):
  614. """
  615. Gets label of a doctype
  616. """
  617. if dt:
  618. res = webnotes.conn.sql("""\
  619. SELECT name, dt_label FROM `tabDocType Label`
  620. WHERE name=%s""", dt)
  621. return res and res[0][0] or dt
  622. else:
  623. res = webnotes.conn.sql("SELECT name, dt_label FROM `tabDocType Label`")
  624. dt_label_dict = {}
  625. for r in res:
  626. dt_label_dict[r[0]] = r[1]
  627. return dt_label_dict
  628. def get_label_doctype(label):
  629. """
  630. Gets doctype from its label
  631. """
  632. res = webnotes.conn.sql("""\
  633. SELECT name FROM `tabDocType Label`
  634. WHERE dt_label=%s""", label)
  635. return res and res[0][0] or label
  636. def pretty_date(iso_datetime):
  637. """
  638. Takes an ISO time and returns a string representing how
  639. long ago the date represents.
  640. Ported from PrettyDate by John Resig
  641. """
  642. if not iso_datetime: return ''
  643. from datetime import datetime
  644. import math
  645. if isinstance(iso_datetime, basestring):
  646. iso_datetime = datetime.strptime(iso_datetime, '%Y-%m-%d %H:%M:%S')
  647. now_dt = datetime.strptime(now(), '%Y-%m-%d %H:%M:%S')
  648. dt_diff = now_dt - iso_datetime
  649. # available only in python 2.7+
  650. # dt_diff_seconds = dt_diff.total_seconds()
  651. dt_diff_seconds = dt_diff.days * 86400.0 + dt_diff.seconds
  652. dt_diff_days = math.floor(dt_diff_seconds / 86400.0)
  653. # differnt cases
  654. if dt_diff_seconds < 60.0:
  655. return 'just now'
  656. elif dt_diff_seconds < 120.0:
  657. return '1 minute ago'
  658. elif dt_diff_seconds < 3600.0:
  659. return '%s minutes ago' % cint(math.floor(dt_diff_seconds / 60.0))
  660. elif dt_diff_seconds < 7200.0:
  661. return '1 hour ago'
  662. elif dt_diff_seconds < 86400.0:
  663. return '%s hours ago' % cint(math.floor(dt_diff_seconds / 3600.0))
  664. elif dt_diff_days == 1.0:
  665. return 'Yesterday'
  666. elif dt_diff_days < 7.0:
  667. return '%s days ago' % cint(dt_diff_days)
  668. elif dt_diff_days < 31.0:
  669. return '%s week(s) ago' % cint(math.ceil(dt_diff_days / 7.0))
  670. elif dt_diff_days < 365.0:
  671. return '%s months ago' % cint(math.ceil(dt_diff_days / 30.0))
  672. else:
  673. return 'more than %s year(s) ago' % cint(math.floor(dt_diff_days / 365.0))
  674. def execute_in_shell(cmd, verbose=0):
  675. # using Popen instead of os.system - as recommended by python docs
  676. from subprocess import Popen, PIPE
  677. p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
  678. # get err and output
  679. err, out = p.stderr.read(), p.stdout.read()
  680. if verbose:
  681. if err: print err
  682. if out: print out
  683. return err, out
  684. def comma_or(some_list):
  685. return comma_sep(some_list, " or ")
  686. def comma_and(some_list):
  687. return comma_sep(some_list, " and ")
  688. def comma_sep(some_list, sep):
  689. if isinstance(some_list, list):
  690. # ([] + some_list) is done to preserve the existing list
  691. some_list = [unicode(s) for s in ([] + some_list)]
  692. if not some_list:
  693. return ""
  694. elif len(some_list) == 1:
  695. return some_list[0]
  696. else:
  697. return ", ".join(some_list[:-1]) + sep + some_list[-1]
  698. else:
  699. return some_list