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 година
пре 11 година
пре 11 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 11 година
пре 11 година
пре 14 година
пре 12 година
пре 13 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 14 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 14 година
пре 13 година
пре 12 година
пре 13 година
пре 14 година
пре 13 година
пре 13 година
пре 12 година
пре 12 година
пре 12 година
пре 11 година
пре 11 година
пре 11 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
  2. # MIT License. See license.txt
  3. # util __init__.py
  4. from __future__ import unicode_literals
  5. from webnotes import conf
  6. import webnotes
  7. user_time_zone = None
  8. user_format = None
  9. current_date = None
  10. no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable',
  11. 'Button', 'Image', 'Graph']
  12. default_fields = ['doctype', 'name', 'owner', 'creation', 'modified', 'modified_by',
  13. 'parent', 'parentfield', 'parenttype', 'idx', 'docstatus']
  14. # used in import_docs.py
  15. # TODO: deprecate it
  16. def getCSVelement(v):
  17. """
  18. Returns the CSV value of `v`, For example:
  19. * apple becomes "apple"
  20. * hi"there becomes "hi""there"
  21. """
  22. v = cstr(v)
  23. if not v: return ''
  24. if (',' in v) or ('\n' in v) or ('"' in v):
  25. if '"' in v: v = v.replace('"', '""')
  26. return '"'+v+'"'
  27. else: return v or ''
  28. def get_fullname(profile):
  29. """get the full name (first name + last name) of the user from Profile"""
  30. p = webnotes.conn.sql("""select first_name, last_name from `tabProfile`
  31. where name=%s""", profile, as_dict=1)
  32. if p:
  33. profile = " ".join(filter(None,
  34. [p[0].get('first_name'), p[0].get('last_name')])) or profile
  35. return profile
  36. def get_formatted_email(user):
  37. """get email id of user formatted as: John Doe <johndoe@example.com>"""
  38. if user == "Administrator":
  39. return user
  40. from email.utils import formataddr
  41. fullname = get_fullname(user)
  42. return formataddr((fullname, user))
  43. def extract_email_id(email):
  44. """fetch only the email part of the email id"""
  45. from email.utils import parseaddr
  46. fullname, email_id = parseaddr(email)
  47. if isinstance(email_id, basestring) and not isinstance(email_id, unicode):
  48. email_id = email_id.decode("utf-8", "ignore")
  49. return email_id
  50. def validate_email_add(email_str):
  51. """Validates the email string"""
  52. email = extract_email_id(email_str)
  53. import re
  54. 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])?", email.lower())
  55. def get_request_site_address(full_address=False):
  56. """get app url from request"""
  57. import os
  58. host_name = conf.host_name
  59. if not host_name:
  60. if webnotes.request:
  61. protocol = 'HTTPS' in webnotes.get_request_header('SERVER_PROTOCOL', "") and 'https://' or 'http://'
  62. host_name = protocol + webnotes.request.host
  63. else:
  64. return "http://localhost"
  65. if full_address:
  66. return host_name + webnotes.get_request_header("REQUEST_URI", "")
  67. else:
  68. return host_name
  69. def random_string(length):
  70. """generate a random string"""
  71. import string
  72. from random import choice
  73. return ''.join([choice(string.letters + string.digits) for i in range(length)])
  74. def load_json(arg):
  75. # already a dictionary?
  76. if not isinstance(arg, basestring):
  77. return arg
  78. import json
  79. return json.loads(arg, encoding='utf-8')
  80. # Get Traceback
  81. # ==============================================================================
  82. def getTraceback():
  83. """
  84. Returns the traceback of the Exception
  85. """
  86. import sys, traceback
  87. exc_type, value, tb = sys.exc_info()
  88. trace_list = traceback.format_tb(tb, None) + \
  89. traceback.format_exception_only(exc_type, value)
  90. body = "Traceback (innermost last):\n" + "%-20s %s" % \
  91. (unicode((b"").join(trace_list[:-1]), 'utf-8'), unicode(trace_list[-1], 'utf-8'))
  92. if webnotes.logger:
  93. webnotes.logger.error('Db:'+(webnotes.conn and webnotes.conn.cur_db_name or '') \
  94. + ' - ' + body)
  95. return body
  96. def log(event, details):
  97. webnotes.logger.info(details)
  98. # datetime functions
  99. def getdate(string_date):
  100. """
  101. Coverts string date (yyyy-mm-dd) to datetime.date object
  102. """
  103. import datetime
  104. if isinstance(string_date, datetime.date):
  105. return string_date
  106. elif isinstance(string_date, datetime.datetime):
  107. return datetime.date()
  108. if " " in string_date:
  109. string_date = string_date.split(" ")[0]
  110. return datetime.datetime.strptime(string_date, "%Y-%m-%d").date()
  111. def add_to_date(date, years=0, months=0, days=0):
  112. """Adds `days` to the given date"""
  113. format = isinstance(date, basestring)
  114. if date:
  115. date = getdate(date)
  116. else:
  117. raise Exception, "Start date required"
  118. from dateutil.relativedelta import relativedelta
  119. date += relativedelta(years=years, months=months, days=days)
  120. if format:
  121. return date.strftime("%Y-%m-%d")
  122. else:
  123. return date
  124. def add_days(date, days):
  125. return add_to_date(date, days=days)
  126. def add_months(date, months):
  127. return add_to_date(date, months=months)
  128. def add_years(date, years):
  129. return add_to_date(date, years=years)
  130. def date_diff(string_ed_date, string_st_date):
  131. return (getdate(string_ed_date) - getdate(string_st_date)).days
  132. def time_diff(string_ed_date, string_st_date):
  133. return get_datetime(string_ed_date) - get_datetime(string_st_date)
  134. def time_diff_in_seconds(string_ed_date, string_st_date):
  135. return time_diff(string_ed_date, string_st_date).seconds
  136. def time_diff_in_hours(string_ed_date, string_st_date):
  137. return round(float(time_diff(string_ed_date, string_st_date).seconds) / 3600, 6)
  138. def now_datetime():
  139. from datetime import datetime
  140. return convert_utc_to_user_timezone(datetime.utcnow())
  141. def get_user_time_zone():
  142. global user_time_zone
  143. if not user_time_zone:
  144. user_time_zone = webnotes.cache().get_value("time_zone")
  145. if not user_time_zone:
  146. user_time_zone = webnotes.conn.get_value('Control Panel', None, 'time_zone') \
  147. or 'Asia/Calcutta'
  148. webnotes.cache().set_value("time_zone", user_time_zone)
  149. return user_time_zone
  150. def convert_utc_to_user_timezone(utc_timestamp):
  151. from pytz import timezone
  152. utcnow = timezone('UTC').localize(utc_timestamp)
  153. return utcnow.astimezone(timezone(get_user_time_zone()))
  154. def now():
  155. """return current datetime as yyyy-mm-dd hh:mm:ss"""
  156. if current_date:
  157. return getdate(current_date).strftime("%Y-%m-%d") + " " + now_datetime().strftime('%H:%M:%S')
  158. else:
  159. return now_datetime().strftime('%Y-%m-%d %H:%M:%S')
  160. def nowdate():
  161. """return current date as yyyy-mm-dd"""
  162. return now_datetime().strftime('%Y-%m-%d')
  163. def today():
  164. return nowdate()
  165. def nowtime():
  166. """return current time in hh:mm"""
  167. return now_datetime().strftime('%H:%M')
  168. def get_first_day(dt, d_years=0, d_months=0):
  169. """
  170. Returns the first day of the month for the date specified by date object
  171. Also adds `d_years` and `d_months` if specified
  172. """
  173. import datetime
  174. dt = getdate(dt)
  175. # d_years, d_months are "deltas" to apply to dt
  176. overflow_years, month = divmod(dt.month + d_months - 1, 12)
  177. year = dt.year + d_years + overflow_years
  178. return datetime.date(year, month + 1, 1)
  179. def get_last_day(dt):
  180. """
  181. Returns last day of the month using:
  182. `get_first_day(dt, 0, 1) + datetime.timedelta(-1)`
  183. """
  184. import datetime
  185. return get_first_day(dt, 0, 1) + datetime.timedelta(-1)
  186. def get_datetime(datetime_str):
  187. from datetime import datetime
  188. if isinstance(datetime_str, datetime):
  189. return datetime_str.replace(microsecond=0, tzinfo=None)
  190. return datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
  191. def get_datetime_str(datetime_obj):
  192. if isinstance(datetime_obj, basestring):
  193. datetime_obj = get_datetime(datetime_obj)
  194. return datetime_obj.strftime('%Y-%m-%d %H:%M:%S')
  195. def formatdate(string_date=None):
  196. """
  197. Convers the given string date to :data:`user_format`
  198. User format specified in :term:`Control Panel`
  199. Examples:
  200. * dd-mm-yyyy
  201. * mm-dd-yyyy
  202. * dd/mm/yyyy
  203. """
  204. if string_date:
  205. string_date = getdate(string_date)
  206. else:
  207. string_date = now_datetime().date()
  208. global user_format
  209. if not user_format:
  210. user_format = webnotes.conn.get_default("date_format")
  211. out = user_format
  212. return out.replace("dd", string_date.strftime("%d"))\
  213. .replace("mm", string_date.strftime("%m"))\
  214. .replace("yyyy", string_date.strftime("%Y"))
  215. def global_date_format(date):
  216. """returns date as 1 January 2012"""
  217. formatted_date = getdate(date).strftime("%d %B %Y")
  218. return formatted_date.startswith("0") and formatted_date[1:] or formatted_date
  219. def dict_to_str(args, sep='&'):
  220. """
  221. Converts a dictionary to URL
  222. """
  223. import urllib
  224. t = []
  225. for k in args.keys():
  226. t.append(str(k)+'='+urllib.quote(str(args[k] or '')))
  227. return sep.join(t)
  228. def timestamps_equal(t1, t2):
  229. """Returns true if same the two string timestamps are same"""
  230. scrub = lambda x: x.replace(':', ' ').replace('-',' ').split()
  231. t1, t2 = scrub(t1), scrub(t2)
  232. if len(t1) != len(t2):
  233. return
  234. for i in range(len(t1)):
  235. if t1[i]!=t2[i]:
  236. return
  237. return 1
  238. def has_common(l1, l2):
  239. """Returns truthy value if there are common elements in lists l1 and l2"""
  240. return set(l1) & set(l2)
  241. def flt(s, precision=None):
  242. """Convert to float (ignore commas)"""
  243. if isinstance(s, basestring):
  244. s = s.replace(',','')
  245. try:
  246. num = float(s)
  247. if precision is not None:
  248. num = _round(num, precision)
  249. except Exception:
  250. num = 0
  251. return num
  252. def cint(s):
  253. """Convert to integer"""
  254. try: num = int(float(s))
  255. except: num = 0
  256. return num
  257. def cstr(s):
  258. if isinstance(s, unicode):
  259. return s
  260. elif s==None:
  261. return ''
  262. elif isinstance(s, basestring):
  263. return unicode(s, 'utf-8')
  264. else:
  265. return unicode(s)
  266. def _round(num, precision=0):
  267. """round method for round halfs to nearest even algorithm"""
  268. precision = cint(precision)
  269. multiplier = 10 ** precision
  270. # avoid rounding errors
  271. num = round(num * multiplier if precision else num, 8)
  272. import math
  273. floor = math.floor(num)
  274. decimal_part = num - floor
  275. if decimal_part == 0.5:
  276. num = floor if (floor % 2 == 0) else floor + 1
  277. else:
  278. num = round(num)
  279. return (num / multiplier) if precision else num
  280. def encode(obj, encoding="utf-8"):
  281. if isinstance(obj, list):
  282. out = []
  283. for o in obj:
  284. if isinstance(o, unicode):
  285. out.append(o.encode(encoding))
  286. else:
  287. out.append(o)
  288. return out
  289. elif isinstance(obj, unicode):
  290. return obj.encode(encoding)
  291. else:
  292. return obj
  293. def parse_val(v):
  294. """Converts to simple datatypes from SQL query results"""
  295. import datetime
  296. if isinstance(v, (datetime.date, datetime.datetime)):
  297. v = unicode(v)
  298. elif isinstance(v, datetime.timedelta):
  299. v = ":".join(unicode(v).split(":")[:2])
  300. elif isinstance(v, long):
  301. v = int(v)
  302. return v
  303. def fmt_money(amount, precision=None, currency=None):
  304. """
  305. Convert to string with commas for thousands, millions etc
  306. """
  307. number_format = webnotes.conn.get_default("number_format") or "#,###.##"
  308. decimal_str, comma_str, precision = get_number_format_info(number_format)
  309. amount = '%.*f' % (precision, flt(amount))
  310. if amount.find('.') == -1:
  311. decimals = ''
  312. else:
  313. decimals = amount.split('.')[1]
  314. parts = []
  315. minus = ''
  316. if flt(amount) < 0:
  317. minus = '-'
  318. amount = cstr(abs(flt(amount))).split('.')[0]
  319. if len(amount) > 3:
  320. parts.append(amount[-3:])
  321. amount = amount[:-3]
  322. val = number_format=="#,##,###.##" and 2 or 3
  323. while len(amount) > val:
  324. parts.append(amount[-val:])
  325. amount = amount[:-val]
  326. parts.append(amount)
  327. parts.reverse()
  328. amount = comma_str.join(parts) + (precision and (decimal_str + decimals) or "")
  329. amount = minus + amount
  330. if currency:
  331. symbol = webnotes.conn.get_value("Currency", currency, "symbol")
  332. if symbol:
  333. amount = symbol + " " + amount
  334. return amount
  335. number_format_info = {
  336. "#.###": ("", ".", 0),
  337. "#,###": ("", ",", 0),
  338. "#,###.##": (".", ",", 2),
  339. "#,##,###.##": (".", ",", 2),
  340. "#.###,##": (",", ".", 2),
  341. "# ###.##": (".", " ", 2),
  342. "#,###.###": (".", ",", 3),
  343. }
  344. def get_number_format_info(format):
  345. return number_format_info.get(format) or (".", ",", 2)
  346. #
  347. # convet currency to words
  348. #
  349. def money_in_words(number, main_currency = None, fraction_currency=None):
  350. """
  351. Returns string in words with currency and fraction currency.
  352. """
  353. d = get_defaults()
  354. if not main_currency:
  355. main_currency = d.get('currency', 'INR')
  356. if not fraction_currency:
  357. fraction_currency = webnotes.conn.get_value("Currency", main_currency, "fraction") or "Cent"
  358. n = "%.2f" % flt(number)
  359. main, fraction = n.split('.')
  360. if len(fraction)==1: fraction += '0'
  361. number_format = webnotes.conn.get_value("Currency", main_currency, "number_format") or \
  362. webnotes.conn.get_default("number_format") or "#,###.##"
  363. in_million = True
  364. if number_format == "#,##,###.##": in_million = False
  365. out = main_currency + ' ' + in_words(main, in_million).title()
  366. if cint(fraction):
  367. out = out + ' and ' + in_words(fraction, in_million).title() + ' ' + fraction_currency
  368. return out + ' only.'
  369. #
  370. # convert number to words
  371. #
  372. def in_words(integer, in_million=True):
  373. """
  374. Returns string in words for the given integer.
  375. """
  376. n=int(integer)
  377. known = {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten',
  378. 11: 'eleven', 12: 'twelve', 13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen', 18: 'eighteen',
  379. 19: 'nineteen', 20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty', 60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'}
  380. def psn(n, known, xpsn):
  381. import sys;
  382. if n in known: return known[n]
  383. bestguess, remainder = str(n), 0
  384. if n<=20:
  385. webnotes.errprint(sys.stderr)
  386. webnotes.errprint(n)
  387. webnotes.errprint("How did this happen?")
  388. assert 0
  389. elif n < 100:
  390. bestguess= xpsn((n//10)*10, known, xpsn) + '-' + xpsn(n%10, known, xpsn)
  391. return bestguess
  392. elif n < 1000:
  393. bestguess= xpsn(n//100, known, xpsn) + ' ' + 'hundred'
  394. remainder = n%100
  395. else:
  396. if in_million:
  397. if n < 1000000:
  398. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  399. remainder = n%1000
  400. elif n < 1000000000:
  401. bestguess= xpsn(n//1000000, known, xpsn) + ' ' + 'million'
  402. remainder = n%1000000
  403. else:
  404. bestguess= xpsn(n//1000000000, known, xpsn) + ' ' + 'billion'
  405. remainder = n%1000000000
  406. else:
  407. if n < 100000:
  408. bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand'
  409. remainder = n%1000
  410. elif n < 10000000:
  411. bestguess= xpsn(n//100000, known, xpsn) + ' ' + 'lakh'
  412. remainder = n%100000
  413. else:
  414. bestguess= xpsn(n//10000000, known, xpsn) + ' ' + 'crore'
  415. remainder = n%10000000
  416. if remainder:
  417. if remainder >= 100:
  418. comma = ','
  419. else:
  420. comma = ''
  421. return bestguess + comma + ' ' + xpsn(remainder, known, xpsn)
  422. else:
  423. return bestguess
  424. return psn(n, known, psn)
  425. # Get Defaults
  426. # ==============================================================================
  427. def get_defaults(key=None):
  428. """
  429. Get dictionary of default values from the :term:`Control Panel`, or a value if key is passed
  430. """
  431. return webnotes.conn.get_defaults(key)
  432. def set_default(key, val):
  433. """
  434. Set / add a default value to :term:`Control Panel`
  435. """
  436. return webnotes.conn.set_default(key, val)
  437. def remove_blanks(d):
  438. """
  439. Returns d with empty ('' or None) values stripped
  440. """
  441. empty_keys = []
  442. for key in d:
  443. if d[key]=='' or d[key]==None:
  444. # del d[key] raises runtime exception, using a workaround
  445. empty_keys.append(key)
  446. for key in empty_keys:
  447. del d[key]
  448. return d
  449. def pprint_dict(d, level=1, no_blanks=True):
  450. """
  451. Pretty print a dictionary with indents
  452. """
  453. if no_blanks:
  454. remove_blanks(d)
  455. # make indent
  456. indent, ret = '', ''
  457. for i in range(0,level): indent += '\t'
  458. # add lines
  459. comment, lines = '', []
  460. kl = d.keys()
  461. kl.sort()
  462. # make lines
  463. for key in kl:
  464. if key != '##comment':
  465. tmp = {key: d[key]}
  466. lines.append(indent + str(tmp)[1:-1] )
  467. # add comment string
  468. if '##comment' in kl:
  469. ret = ('\n' + indent) + '# ' + d['##comment'] + '\n'
  470. # open
  471. ret += indent + '{\n'
  472. # lines
  473. ret += indent + ',\n\t'.join(lines)
  474. # close
  475. ret += '\n' + indent + '}'
  476. return ret
  477. def get_common(d1,d2):
  478. """
  479. returns (list of keys) the common part of two dicts
  480. """
  481. return [p for p in d1 if p in d2 and d1[p]==d2[p]]
  482. def get_common_dict(d1, d2):
  483. """
  484. return common dictionary of d1 and d2
  485. """
  486. ret = {}
  487. for key in d1:
  488. if key in d2 and d2[key]==d1[key]:
  489. ret[key] = d1[key]
  490. return ret
  491. def get_diff_dict(d1, d2):
  492. """
  493. return common dictionary of d1 and d2
  494. """
  495. diff_keys = set(d2.keys()).difference(set(d1.keys()))
  496. ret = {}
  497. for d in diff_keys: ret[d] = d2[d]
  498. return ret
  499. def get_file_timestamp(fn):
  500. """
  501. Returns timestamp of the given file
  502. """
  503. import os
  504. from webnotes.utils import cint
  505. try:
  506. return str(cint(os.stat(fn).st_mtime))
  507. except OSError, e:
  508. if e.args[0]!=2:
  509. raise e
  510. else:
  511. return None
  512. # to be deprecated
  513. def make_esc(esc_chars):
  514. """
  515. Function generator for Escaping special characters
  516. """
  517. return lambda s: ''.join(['\\' + c if c in esc_chars else c for c in s])
  518. # esc / unescape characters -- used for command line
  519. def esc(s, esc_chars):
  520. """
  521. Escape special characters
  522. """
  523. if not s:
  524. return ""
  525. for c in esc_chars:
  526. esc_str = '\\' + c
  527. s = s.replace(c, esc_str)
  528. return s
  529. def unesc(s, esc_chars):
  530. """
  531. UnEscape special characters
  532. """
  533. for c in esc_chars:
  534. esc_str = '\\' + c
  535. s = s.replace(esc_str, c)
  536. return s
  537. def is_html(text):
  538. out = False
  539. for key in ["<br>", "<p", "<img", "<div"]:
  540. if key in text:
  541. out = True
  542. break
  543. return out
  544. def strip_html(text):
  545. """
  546. removes anything enclosed in and including <>
  547. """
  548. import re
  549. return re.compile(r'<.*?>').sub('', text)
  550. def escape_html(text):
  551. html_escape_table = {
  552. "&": "&amp;",
  553. '"': "&quot;",
  554. "'": "&apos;",
  555. ">": "&gt;",
  556. "<": "&lt;",
  557. }
  558. return "".join(html_escape_table.get(c,c) for c in text)
  559. def get_doctype_label(dt=None):
  560. """
  561. Gets label of a doctype
  562. """
  563. if dt:
  564. res = webnotes.conn.sql("""\
  565. SELECT name, dt_label FROM `tabDocType Label`
  566. WHERE name=%s""", dt)
  567. return res and res[0][0] or dt
  568. else:
  569. res = webnotes.conn.sql("SELECT name, dt_label FROM `tabDocType Label`")
  570. dt_label_dict = {}
  571. for r in res:
  572. dt_label_dict[r[0]] = r[1]
  573. return dt_label_dict
  574. def get_label_doctype(label):
  575. """
  576. Gets doctype from its label
  577. """
  578. res = webnotes.conn.sql("""\
  579. SELECT name FROM `tabDocType Label`
  580. WHERE dt_label=%s""", label)
  581. return res and res[0][0] or label
  582. def pretty_date(iso_datetime):
  583. """
  584. Takes an ISO time and returns a string representing how
  585. long ago the date represents.
  586. Ported from PrettyDate by John Resig
  587. """
  588. if not iso_datetime: return ''
  589. from datetime import datetime
  590. import math
  591. if isinstance(iso_datetime, basestring):
  592. iso_datetime = datetime.strptime(iso_datetime, '%Y-%m-%d %H:%M:%S')
  593. now_dt = datetime.strptime(now(), '%Y-%m-%d %H:%M:%S')
  594. dt_diff = now_dt - iso_datetime
  595. # available only in python 2.7+
  596. # dt_diff_seconds = dt_diff.total_seconds()
  597. dt_diff_seconds = dt_diff.days * 86400.0 + dt_diff.seconds
  598. dt_diff_days = math.floor(dt_diff_seconds / 86400.0)
  599. # differnt cases
  600. if dt_diff_seconds < 60.0:
  601. return 'just now'
  602. elif dt_diff_seconds < 120.0:
  603. return '1 minute ago'
  604. elif dt_diff_seconds < 3600.0:
  605. return '%s minutes ago' % cint(math.floor(dt_diff_seconds / 60.0))
  606. elif dt_diff_seconds < 7200.0:
  607. return '1 hour ago'
  608. elif dt_diff_seconds < 86400.0:
  609. return '%s hours ago' % cint(math.floor(dt_diff_seconds / 3600.0))
  610. elif dt_diff_days == 1.0:
  611. return 'Yesterday'
  612. elif dt_diff_days < 7.0:
  613. return '%s days ago' % cint(dt_diff_days)
  614. elif dt_diff_days < 31.0:
  615. return '%s week(s) ago' % cint(math.ceil(dt_diff_days / 7.0))
  616. elif dt_diff_days < 365.0:
  617. return '%s months ago' % cint(math.ceil(dt_diff_days / 30.0))
  618. else:
  619. return 'more than %s year(s) ago' % cint(math.floor(dt_diff_days / 365.0))
  620. def execute_in_shell(cmd, verbose=0):
  621. # using Popen instead of os.system - as recommended by python docs
  622. from subprocess import Popen
  623. import tempfile
  624. with tempfile.TemporaryFile() as stdout:
  625. with tempfile.TemporaryFile() as stderr:
  626. p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
  627. p.wait()
  628. stdout.seek(0)
  629. out = stdout.read()
  630. stderr.seek(0)
  631. err = stderr.read()
  632. if verbose:
  633. if err: print err
  634. if out: print out
  635. return err, out
  636. def comma_or(some_list):
  637. return comma_sep(some_list, " or ")
  638. def comma_and(some_list):
  639. return comma_sep(some_list, " and ")
  640. def comma_sep(some_list, sep):
  641. if isinstance(some_list, (list, tuple)):
  642. # list(some_list) is done to preserve the existing list
  643. some_list = [unicode(s) for s in list(some_list)]
  644. if not some_list:
  645. return ""
  646. elif len(some_list) == 1:
  647. return some_list[0]
  648. else:
  649. some_list = ["'%s'" % s for s in some_list]
  650. return ", ".join(some_list[:-1]) + sep + some_list[-1]
  651. else:
  652. return some_list
  653. def filter_strip_join(some_list, sep):
  654. """given a list, filter None values, strip spaces and join"""
  655. return (cstr(sep)).join((cstr(a).strip() for a in filter(None, some_list)))
  656. def get_path(base=None, *path):
  657. if not base:
  658. base = get_base_path()
  659. import os
  660. return os.path.join(base, *path)
  661. def get_base_path():
  662. import conf
  663. import os
  664. return os.path.dirname(os.path.abspath(conf.__file__))
  665. def get_storage_base_path(sites_dir=None, hostname=None):
  666. import os
  667. if not sites_dir and not hostname:
  668. sites_dir = conf.sites_dir
  669. hostname = conf.site
  670. return os.path.join(sites_dir, hostname)
  671. def get_storage_path(*path):
  672. return get_path(base=get_storage_base_path(), *path)
  673. def get_url(uri=None):
  674. url = get_request_site_address()
  675. if not url or "localhost" in url:
  676. subdomain = webnotes.conn.get_value("Website Settings", "Website Settings",
  677. "subdomain")
  678. if subdomain:
  679. if "http" not in subdomain:
  680. url = "http://" + subdomain
  681. if uri:
  682. import urllib
  683. url = urllib.basejoin(url, uri)
  684. return url
  685. def get_url_to_form(doctype, name, base_url=None, label=None):
  686. if not base_url:
  687. base_url = get_url()
  688. if not label: label = name
  689. return """<a href="%(base_url)s/app.html#!Form/%(doctype)s/%(name)s">%(label)s</a>""" % locals()
  690. def encode_dict(d, encoding="utf-8"):
  691. for key in d:
  692. if isinstance(d[key], basestring) and isinstance(d[key], unicode):
  693. d[key] = d[key].encode(encoding)
  694. return d
  695. def decode_dict(d, encoding="utf-8"):
  696. for key in d:
  697. if isinstance(d[key], basestring) and not isinstance(d[key], unicode):
  698. d[key] = d[key].decode(encoding, "ignore")
  699. return d
  700. import operator
  701. operator_map = {
  702. # startswith
  703. "^": lambda (a, b): (a or "").startswith(b),
  704. # in or not in a list
  705. "in": lambda (a, b): operator.contains(b, a),
  706. "not in": lambda (a, b): not operator.contains(b, a),
  707. # comparison operators
  708. "=": lambda (a, b): operator.eq(a, b),
  709. "!=": lambda (a, b): operator.ne(a, b),
  710. ">": lambda (a, b): operator.gt(a, b),
  711. "<": lambda (a, b): operator.lt(a, b),
  712. ">=": lambda (a, b): operator.ge(a, b),
  713. "<=": lambda (a, b): operator.le(a, b),
  714. "not None": lambda (a, b): a and True or False,
  715. "None": lambda (a, b): (not a) and True or False
  716. }
  717. def compare(val1, condition, val2):
  718. if condition in operator_map:
  719. return operator_map[condition]((val1, val2))
  720. return False