/parampool/generator/django/generate_views.py

https://github.com/hplgit/parampool · Python · 678 lines · 646 code · 23 blank · 9 comment · 41 complexity · 4bd5cc2239973c9a8ff02d91326c49c3 MD5 · raw file

  1. def generate_views(compute_function,
  2. classname,
  3. outfile,
  4. filename_template,
  5. pool_function,
  6. filename_models,
  7. login):
  8. models_module = filename_models.strip(".py")
  9. compute_function_name = compute_function.__name__
  10. compute_function_file = compute_function.__module__
  11. if pool_function:
  12. pool_function_name = pool_function.__name__
  13. pool_function_file = pool_function.__module__
  14. pool = True
  15. else:
  16. pool = False
  17. import inspect
  18. arg_names = inspect.getargspec(compute_function).args
  19. defaults = inspect.getargspec(compute_function).defaults
  20. # Add code for file upload only if it is strictly needed
  21. file_upload = False
  22. if pool:
  23. # FIXME: This should be replaced by a good regex
  24. filetxt = ("widget='file'", 'widget="file"',
  25. "widget = 'file'", 'widget = "file"')
  26. pooltxt = open(pool_function_file + ".py", 'r').read()
  27. for txt in filetxt:
  28. if txt in pooltxt:
  29. file_upload = True
  30. break
  31. else:
  32. for name in arg_names:
  33. if 'filename' in name:
  34. file_upload = True
  35. break
  36. code = '''\
  37. from %(compute_function_file)s import %(compute_function_name)s as compute_function
  38. ''' % vars()
  39. if pool:
  40. code += '''
  41. # Pool object (must be imported before %(models_module)s
  42. from %(pool_function_file)s import %(pool_function_name)s as pool_function
  43. pool = pool_function()
  44. # Can define other default values in a file: --poolfile name
  45. from parampool.pool.UI import set_defaults_from_file
  46. pool = set_defaults_from_file(pool)
  47. # Can override default values on the command line
  48. from parampool.pool.UI import set_values_from_command_line
  49. pool = set_values_from_command_line(pool)
  50. ''' % vars()
  51. code += '''
  52. from django.shortcuts import render_to_response
  53. from django.template import RequestContext
  54. from %(models_module)s import %(classname)s, %(classname)sForm
  55. ''' % vars()
  56. if login:
  57. code += '''\
  58. from %(models_module)s import %(classname)sUser
  59. from %(models_module)s import %(classname)sUserForm
  60. from forms import CreateNewLoginForm, LoginForm
  61. from django.contrib.auth import authenticate, login, logout
  62. from django.contrib.auth.models import User
  63. from django.db import IntegrityError
  64. from django.http import HttpResponse, HttpResponseRedirect
  65. ''' % vars()
  66. if file_upload:
  67. code += '''
  68. import os
  69. UPLOAD_DIR = os.path.join(os.path.dirname(__file__), "uploads")
  70. if not os.path.isdir(UPLOAD_DIR):
  71. os.mkdir(UPLOAD_DIR)
  72. '''
  73. code += '''
  74. def index(request):
  75. result = None
  76. '''
  77. if login:
  78. code += '''\
  79. user = request.user
  80. '''
  81. if file_upload and pool:
  82. if login:
  83. code += '''
  84. form = %(classname)sForm(request.POST or None, request.FILES or None)
  85. if request.method == 'POST':
  86. # User is logged in
  87. if request.user.is_authenticated():
  88. data = request.POST.copy()
  89. data['user'] = user.id
  90. form = %(classname)sUserForm(data, request.FILES or None)
  91. if form.is_valid():
  92. for field in form:
  93. if field.name in ("user", "result", "comments"):
  94. continue
  95. name = %(classname)s._meta.get_field(field.name).verbose_name.strip()
  96. value = field.data
  97. if field.name in request.FILES:
  98. filename = field.data.name
  99. data_item = pool.set_value(name, filename)
  100. with open(os.path.join(UPLOAD_DIR, filename), 'wb+') as destination:
  101. for chunk in field.data.chunks():
  102. destination.write(chunk)
  103. else:
  104. data_item = pool.set_value(name, value)
  105. f = form.save(commit=False)
  106. result = compute(pool)
  107. if user.email:
  108. user.email_user("%(classname)s Computations Complete", """\
  109. A simulation has been completed by the Django %(classname)s app. Please log in at
  110. http://localhost:8000/login
  111. to see the results.
  112. ---
  113. This email has been automatically generated by the %(classname)s app created by
  114. Parampool. If you don't want email notifications when a result is found, please
  115. register a new user and leave the email field blank.""")
  116. # Save to db
  117. f.result = result
  118. f.save()
  119. # Anonymous user
  120. else:
  121. if form.is_valid():
  122. for field in form:
  123. name = %(classname)s._meta.get_field(field.name).verbose_name.strip()
  124. value = field.data
  125. if field.name in request.FILES:
  126. filename = field.data.name
  127. pool.set_value(name, filename)
  128. with open(os.path.join(UPLOAD_DIR, filename), 'wb+') as destination:
  129. for chunk in field.data.chunks():
  130. destination.write(chunk)
  131. else:
  132. pool.set_value(name, value)
  133. result = compute(pool)
  134. form = %(classname)sForm(request.POST, request.FILES)
  135. else:
  136. # Retrieve previous result and input if user is logged in
  137. if request.user.is_authenticated():
  138. # FIXME: Find out why this fails when there are no objects
  139. # and find a better way to deal with the error.
  140. try:
  141. objects = %(classname)sUser.objects.filter(user=user)
  142. if len(objects) > 0:
  143. # Negative indexing not allowed.
  144. instance = objects[len(objects)-1]
  145. form = %(classname)sForm(instance=instance)
  146. result = instance.result
  147. except:
  148. pass
  149. ''' % vars()
  150. else:
  151. code += '''
  152. form = %(classname)sForm(request.POST or None, request.FILES or None)
  153. if request.method == 'POST' and form.is_valid():
  154. for field in form:
  155. name = %(classname)s._meta.get_field(field.name).verbose_name.strip()
  156. value = field.data
  157. if field.name in request.FILES:
  158. filename = field.data.name
  159. pool.set_value(name, filename)
  160. with open(os.path.join(UPLOAD_DIR, filename), 'wb+') as destination:
  161. for chunk in field.data.chunks():
  162. destination.write(chunk)
  163. else:
  164. pool.set_value(name, value)
  165. result = compute(pool)
  166. form = %(classname)sForm(request.POST, request.FILES)
  167. ''' % vars()
  168. elif file_upload and not pool:
  169. if login:
  170. code += '''
  171. filename = None
  172. form = %(classname)sForm(request.POST or None, request.FILES or None)
  173. if request.method == 'POST':
  174. # User is logged in
  175. if request.user.is_authenticated():
  176. data = request.POST.copy()
  177. data['user'] = user.id
  178. form = %(classname)sUserForm(data, request.FILES or None)
  179. if form.is_valid():
  180. for field in form:
  181. if field.name in request.FILES:
  182. filename = field.data.name
  183. with open(os.path.join(UPLOAD_DIR, filename), 'wb+') as destination:
  184. for chunk in field.data.chunks():
  185. destination.write(chunk)
  186. f = form.save(commit=False)
  187. result = compute(f, request)
  188. if user.email:
  189. user.email_user("%(classname)s Computations Complete", """\
  190. A simulation has been completed by the Django %(classname)s app. Please log in at
  191. http://localhost:8000/login
  192. to see the results.
  193. ---
  194. This email has been automatically generated by the %(classname)s app created by
  195. Parampool. If you don't want email notifications when a result is found, please
  196. register a new user and leave the email field blank.""")
  197. # Save to db
  198. f.result = result
  199. f.save()
  200. # Anonymous user
  201. else:
  202. #form = %(classname)sForm(request.POST or None, request.FILES or None)
  203. if form.is_valid():
  204. for field in form:
  205. if field.name in request.FILES:
  206. filename = field.data.name
  207. with open(os.path.join(UPLOAD_DIR, filename), 'wb+') as destination:
  208. for chunk in field.data.chunks():
  209. destination.write(chunk)
  210. form = form.save(commit=False)
  211. request.session["filename"] = filename
  212. result = compute(form, request)
  213. form = %(classname)sForm(request.POST, request.FILES)
  214. else:
  215. # Retrieve previous result and input if user is logged in
  216. if request.user.is_authenticated():
  217. # FIXME: Find out why this fails when there are no objects
  218. # and find a better way to deal with the error.
  219. try:
  220. objects = %(classname)sUser.objects.filter(user=user)
  221. if len(objects) > 0:
  222. # Negative indexing not allowed.
  223. instance = objects[len(objects)-1]
  224. form = %(classname)sForm(instance=instance)
  225. result = instance.result
  226. except:
  227. pass
  228. ''' % vars()
  229. else:
  230. code += '''
  231. filename = None
  232. form = %(classname)sForm(request.POST or None, request.FILES or None)
  233. if request.method == 'POST' and form.is_valid():
  234. for field in form:
  235. if field.name in request.FILES:
  236. filename = field.data.name
  237. with open(os.path.join(UPLOAD_DIR, filename), 'wb+') as destination:
  238. for chunk in field.data.chunks():
  239. destination.write(chunk)
  240. form = form.save(commit=False)
  241. request.session["filename"] = filename
  242. result = compute(form, request)
  243. form = %(classname)sForm(request.POST, request.FILES)
  244. ''' % vars()
  245. elif not file_upload and pool:
  246. if login:
  247. code += '''
  248. form = %(classname)sForm(request.POST or None)
  249. if request.method == 'POST':
  250. # User is logged in
  251. if request.user.is_authenticated():
  252. data = request.POST.copy()
  253. data['user'] = user.id
  254. form = %(classname)sUserForm(data)
  255. if form.is_valid():
  256. for field in form:
  257. if field.name not in ("user", "result", "comments"):
  258. name = %(classname)s._meta.get_field(field.name).verbose_name.strip()
  259. value = field.data
  260. pool.set_value(name, value)
  261. f = form.save(commit=False)
  262. result = compute(pool)
  263. if user.email:
  264. user.email_user("%(classname)s Computations Complete", """\
  265. A simulation has been completed by the Django %(classname)s app. Please log in at
  266. http://localhost:8000/login
  267. to see the results.
  268. ---
  269. This email has been automatically generated by the %(classname)s app created by
  270. Parampool. If you don't want email notifications when a result is found, please
  271. register a new user and leave the email field blank.""")
  272. # Save to db
  273. f.result = result
  274. f.save()
  275. # Anonymous user
  276. else:
  277. if form.is_valid():
  278. for field in form:
  279. name = %(classname)s._meta.get_field(field.name).verbose_name.strip()
  280. value = field.data
  281. pool.set_value(name, value)
  282. result = compute(pool)
  283. form = %(classname)sForm(request.POST, request.FILES)
  284. else:
  285. # Retrieve previous result and input if user is logged in
  286. if request.user.is_authenticated():
  287. # FIXME: Find out why this fails when there are no objects
  288. # and find a better way to deal with the error.
  289. try:
  290. objects = %(classname)sUser.objects.filter(user=user)
  291. if len(objects) > 0:
  292. # Negative indexing not allowed.
  293. instance = objects[len(objects)-1]
  294. form = %(classname)sForm(instance=instance)
  295. result = instance.result
  296. except:
  297. pass
  298. ''' % vars()
  299. else:
  300. code += '''
  301. form = %(classname)sForm(request.POST or None)
  302. if request.method == 'POST' and form.is_valid():
  303. for field in form:
  304. name = %(classname)s._meta.get_field(field.name).verbose_name.strip()
  305. value = field.data
  306. pool.set_value(name, value)
  307. result = compute(pool)
  308. form = %(classname)sForm(request.POST)
  309. ''' % vars()
  310. else:
  311. if login:
  312. code += '''
  313. form = %(classname)sForm(request.POST or None)
  314. if request.method == 'POST':
  315. # User is logged in
  316. if request.user.is_authenticated():
  317. data = request.POST.copy()
  318. data['user'] = user.id
  319. form = %(classname)sUserForm(data)
  320. if form.is_valid():
  321. f = form.save(commit=False)
  322. result = compute(f)
  323. if user.email:
  324. user.email_user("%(classname)s Computations Complete", """\
  325. A simulation has been completed by the Django %(classname)s app. Please log in at
  326. http://localhost:8000/login
  327. to see the results.
  328. ---
  329. This email has been automatically generated by the %(classname)s app created by
  330. Parampool. If you don't want email notifications when a result is found, please
  331. register a new user and leave the email field blank.""")
  332. # Save to db
  333. f.result = result
  334. f.save()
  335. # Anonymous user
  336. else:
  337. if form.is_valid():
  338. result = compute(form)
  339. form = %(classname)sForm(request.POST, request.FILES)
  340. else:
  341. # Retrieve previous result and input if user is logged in
  342. if request.user.is_authenticated():
  343. # FIXME: Find out why this fails when there are no objects
  344. # and find a better way to deal with the error.
  345. try:
  346. objects = %(classname)sUser.objects.filter(user=user)
  347. if len(objects) > 0:
  348. # Negative indexing not allowed.
  349. instance = objects[len(objects)-1]
  350. form = %(classname)sForm(instance=instance)
  351. result = instance.result
  352. except:
  353. pass
  354. ''' % vars()
  355. else:
  356. code += '''
  357. form = %(classname)sForm(request.POST or None)
  358. if request.method == 'POST' and form.is_valid():
  359. form = form.save(commit=False)
  360. result = compute(form)
  361. form = %(classname)sForm(request.POST or None)
  362. ''' % vars()
  363. code += '''
  364. return render_to_response(
  365. "%(filename_template)s",
  366. {"form": form,
  367. "result": result,
  368. ''' % vars()
  369. if login:
  370. code += '''\
  371. "user": user,
  372. '''
  373. code += '''\
  374. },
  375. context_instance=RequestContext(request))
  376. ''' % vars()
  377. if pool:
  378. code += '''
  379. def compute(pool):
  380. """
  381. Generic function for calling compute_function with values
  382. taken from the pool object.
  383. Return the output from the compute_function.
  384. """
  385. # compute_function must have only one positional argument
  386. # named pool
  387. import inspect
  388. arg_names = inspect.getargspec(compute_function).args
  389. if len(arg_names) == 1 and arg_names[0] == "pool":
  390. result = compute_function(pool)
  391. else:
  392. raise TypeError('%s(%s) can only have one argument named "pool"'
  393. % (compute_function.__name__, ', '.join(arg_names)))
  394. return result
  395. '''
  396. else:
  397. if file_upload:
  398. code += '''
  399. def compute(form, request):
  400. '''
  401. else:
  402. code += '''
  403. def compute(form):
  404. '''
  405. code += '''\
  406. """
  407. Generic function for compute_function with arguments
  408. taken from a form object (django.forms.ModelForm subclass).
  409. Return the output from the compute_function.
  410. """
  411. # Extract arguments to the compute function
  412. import inspect
  413. arg_names = inspect.getargspec(compute_function).args
  414. '''
  415. if file_upload:
  416. code += '''
  417. form_data = []
  418. for name in arg_names:
  419. if name == "filename":
  420. if request.user.is_authenticated():
  421. filename = getattr(form, name).name
  422. form_data.append(filename or None)
  423. else:
  424. form_data.append(request.session.get("filename"))
  425. else:
  426. if hasattr(form, name):
  427. form_data.append(getattr(form, name))
  428. '''
  429. else:
  430. code += '''
  431. # Extract values from form
  432. form_data = [getattr(form, name) for name in arg_names
  433. if hasattr(form, name)]
  434. '''
  435. # Give a warning and insert helper code if positional
  436. # arguments because the user must then convert form_data
  437. # elements explicitly.
  438. import inspect
  439. arg_names = inspect.getargspec(compute_function).args
  440. defaults = inspect.getargspec(compute_function).defaults
  441. if defaults is not None and len(defaults) != len(arg_names):
  442. # Insert example on argument conversion since there are
  443. # positional arguments where default_field might be the
  444. # wrong type
  445. code += '''
  446. # Convert data to right types (if necessary)
  447. # for i in range(len(form_data)):
  448. # name = arg_names[i]
  449. # if name == '...':
  450. # form_data[i] = int(form_data[i])
  451. # elif name == '...':
  452. '''
  453. else:
  454. # We have default values: do right conversions
  455. code += '''
  456. defaults = inspect.getargspec(compute_function).defaults
  457. # Make defaults as long as arg_names so we can traverse both with zip
  458. if defaults:
  459. defaults = ["none"]*(len(arg_names)-len(defaults)) + list(defaults)
  460. else:
  461. defaults = ["none"]*len(arg_names)
  462. # Convert form data to the right type:
  463. import numpy
  464. for i in range(len(form_data)):
  465. if defaults[i] != "none":
  466. #if isinstance(defaults[i], (str,bool,int,float)): # bool not ready
  467. if isinstance(defaults[i], (str,int,float)):
  468. pass # special widgets for these types do the conversion
  469. elif isinstance(defaults[i], numpy.ndarray):
  470. form_data[i] = numpy.array(eval(form_data[i]))
  471. elif defaults[i] is None:
  472. if form_data[i] == 'None':
  473. form_data[i] = None
  474. else:
  475. try:
  476. # Try eval if it succeeds...
  477. form_data[i] = eval(form_data[i])
  478. except:
  479. pass # Just keep the text
  480. else:
  481. # Use eval to convert to right type (hopefully)
  482. try:
  483. form_data[i] = eval(form_data[i])
  484. except:
  485. print 'Could not convert text %s to %s for argument %s' % (form_data[i], type(defaults[i]), arg_names[i])
  486. print 'when calling the compute function...'
  487. '''
  488. code += '''
  489. # Run computations
  490. result = compute_function(*form_data)
  491. return result
  492. ''' % vars()
  493. if login:
  494. code += '''
  495. def add_comment(request):
  496. if request.method == 'POST':
  497. try:
  498. objects = %(classname)sUser.objects.filter(user=request.user)
  499. if len(objects) > 0:
  500. instance = objects[len(objects)-1]
  501. instance.delete()
  502. form = %(classname)sUserForm(instance=instance)
  503. f = form.save(commit=False)
  504. f.comments = request.POST.get("comments", None)
  505. f.save()
  506. form = %(classname)sForm(instance=instance)
  507. result = instance.result
  508. except:
  509. pass
  510. return HttpResponseRedirect("/")
  511. def create_login(request):
  512. """
  513. Create a login for a new user.
  514. """
  515. form = CreateNewLoginForm()
  516. if request.POST:
  517. form = CreateNewLoginForm(request.POST)
  518. if form.is_valid():
  519. newuser = User()
  520. username = form.cleaned_data['username']
  521. pw = form.cleaned_data['password']
  522. newuser.username = username
  523. newuser.set_password(pw)
  524. newuser.email = form.cleaned_data['email']
  525. newuser.save()
  526. user = authenticate(username=username, password=pw)
  527. login(request, user)
  528. return HttpResponseRedirect('/')
  529. return render_to_response('reg.html', {'form' : form},
  530. context_instance=RequestContext(request))
  531. def login_func(request):
  532. form = LoginForm()
  533. if request.POST:
  534. form = LoginForm(request.POST)
  535. if form.is_valid():
  536. username = form.cleaned_data['username']
  537. password = form.cleaned_data['password']
  538. user = authenticate(username=username, password=password)
  539. if user:
  540. if user.is_authenticated():
  541. if user.is_active:
  542. login(request, user)
  543. return HttpResponseRedirect('/')
  544. else:
  545. return HttpRespose("Account disabled")
  546. else:
  547. return HttpResponse("Invalid login")
  548. else:
  549. return HttpResponse("Invalid login")
  550. return render_to_response("login.html", {'form' : form},
  551. context_instance=RequestContext(request))
  552. def logout_func(request):
  553. logout(request)
  554. return HttpResponseRedirect('/')
  555. def old(request):
  556. forms = []
  557. results = []
  558. if request.user.is_authenticated():
  559. user = request.user
  560. try:
  561. objects = %(classname)sUser.objects.filter(user=user)
  562. counter = len(objects) - 1
  563. while counter >= 0:
  564. instance = objects[counter]
  565. forms.append(%(classname)sForm(instance=instance))
  566. result = instance.result
  567. if instance.comments:
  568. result += "<h3>Comments</h3>" + instance.comments
  569. results.append(result)
  570. counter -= 1
  571. except:
  572. pass
  573. import itertools
  574. iterator = itertools.count()
  575. return render_to_response("old.html",
  576. {"forms": forms,
  577. "results": results,
  578. "iterator": iterator},
  579. context_instance=RequestContext(request))
  580. def delete(request, id):
  581. id = int(id)
  582. objects = %(classname)sUser.objects.filter(user=request.user)
  583. if id == -1:
  584. objects.delete()
  585. elif id in range(len(objects)):
  586. instance = objects[len(objects)-id-1]
  587. instance.delete()
  588. return HttpResponseRedirect('/old/')
  589. ''' % vars()
  590. if pool:
  591. code += """
  592. from parampool.pool.UI import write_poolfile
  593. write_poolfile(pool, '.tmp_pool.dat')
  594. """
  595. if outfile is None:
  596. return code
  597. else:
  598. out = open(outfile, 'w')
  599. out.write(code)
  600. out.close()