Advertisement
Guest User

Untitled

a guest
May 30th, 2017
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.77 KB | None | 0 0
  1. Renderer overhaul
  2. ------------------
  3.  
  4. Currently the division of responsibility between the BFG configurator
  5. and a BFG renderer implementation is awkward and wrong.
  6.  
  7. - Renderer factories have no ability to convert a raw ``renderer=``
  8. path (e.g. ``templates/foo.pt```) into something internally
  9. meaningful. Instead, BFG mangles the string into a package-relative
  10. spec before it is passed to the renderer factory. This is wrong, as
  11. some renderers may not be interested in package-relative specs at
  12. all (for instance, loader-style renderers which have a hardcoded set
  13. of template locations). The reason, however, that BFG currently
  14. does it this way is that the raw renderer path alone does not
  15. contain enough information itself to be useful; knowledge of the
  16. *package* is also required for package-based renderers to make sense
  17. of relative renderer strings (e.g. ``templates/foo.pt`` could mean
  18. the ``templates/foo.pt`` file within the ``mypackage`` package).
  19.  
  20. To fix this, we need to provide some way to pass the package name to
  21. the renderer factory as well as the renderer path. But the package
  22. name isn't the only thing an *arbitrary* renderer might need.
  23. Another renderer might need, for example, a deployment setting. So
  24. we'll need to identify all the crap that *might* be useful to a
  25. renderer factory and we'll need to pass all of it into the renderer
  26. factory as a garbage barge dictionary; individual renderers will
  27. make use of whatever they can from that garbage barge dictionary.
  28. Garbage barge dict item candidates: ``package`` (the "current"
  29. package), ``config`` (the configurator), ``package_name`` (the
  30. current package's ``__name__``), ``settings`` (the deployment
  31. settings), ``registry`` (the component registry).
  32.  
  33. - A BFG renderer currently returns a *string*. It would be more
  34. symmetric if a renderer always returned a Response object. Then the
  35. calling machinery inside BFG could treat a view which happened to
  36. use a renderer exactly the same as a view which returns a response
  37. directly. Maybe. Problem: varying response attributes such as
  38. ``content-type``, etc only makes sense when the view callable uses a
  39. renderer; not when it doesn't, so there's some asymmetry there.
  40. Maybe we make renderers return Responses, but still keep the
  41. attribute-inspection stuff inside BFG, only used when we call a view
  42. which we know uses a renderer. We *could* always call the attribute
  43. inspection stuff, but it would be a slowdown in cases where views
  44. really do always return a Response directly.
  45.  
  46. - The ``system`` value passed to a renderer is not extensible. It
  47. should be extensible on a per-application basis. For example, you
  48. might want to add a top-level variable ``c`` to the values passed to
  49. all renderers representing a template context to emulate Pylons.
  50.  
  51. - ``repoze.bfg.chameleon_zpt.render_template_to_response``, et. al. do
  52. not use the same machinery as view renderers. It would be useful if
  53. templates rendered with ``render_template_to_response`` had the same
  54. ``system`` values available to it as templates renderered via a view
  55. renderer.
  56.  
  57. To at least partially ameliorate the above, renderer factories should
  58. be changed to things that have a set of interfaces something like
  59. this::
  60.  
  61. class IRendererFactory(Interface):
  62. def __call__(path, info):
  63. "" Return an IRenderer."""
  64.  
  65. class IRenderer(Interface):
  66. def __call__(value, system):
  67. """ Return a Response """
  68.  
  69. A semi-pseudocode example:
  70.  
  71. from webob import Response
  72.  
  73. class SampleRendererFactory(object):
  74. def __init__(self, **config):
  75. self.config = config
  76.  
  77. def __call__(self, path, info):
  78. path = do_something_to_evaluate_path_using_info(path, info)
  79. search_path = self.config['search_path']
  80. debug = self.config['debug']
  81. def renderer(value, system):
  82. string = do_rendering(search_path, debug, path, value, system)
  83. return Response(string)
  84. return renderer
  85.  
  86. if __name__ == '__main__':
  87.  
  88. def view1(request):
  89. return {'a':1}
  90.  
  91. def view2(request):
  92. return {'a':2}
  93.  
  94. renderer_factory = SampleRendererFactory(search_path=['/a', '/b'])
  95.  
  96. package_name = 'some.package'
  97.  
  98. for view, path in [
  99. (view1, 'templates/foo.pt'),
  100. (view2, 'templates/bar.pt'),
  101. ]:
  102. renderer = renderer_factory(path, dict(package_name=package_name))
  103. register_renderer_for_view(renderer, view)
  104.  
  105. This is mostly an amelioration for the first and second bullet points
  106. above. The second two bullet points are not addressed by it.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement