Step 03: Hello World in Chameleon

Most web systems feature template languages for generating HTML. This lets a UX person focus on the thing they know (markup) and sprinkle in code, rather than the reverse.

Pyramid doesn’t have too much of an opinion on templating languages. This tutorial does though. We’re Chameleon/ZPT folks. So let’s do “hello world” using a page template.

Goals

  • Simplest step possible to bring in a template

Objectives

  • Move the views out to a separate module
  • Change application.py to scan a module for view declarations
  • Illustrate the coolness of renderers and data-oriented views, particularly for testing
  • Modify tests to be data-oriented

Steps

  1. Remember that Tutorial Setup said to do $ export PYRAMID_RELOAD_TEMPLATES=1 lets you edit templates and not have to restart your Pyramid application.

  2. $ cd ../../creatingux; mkdir step03; cd step03

  3. Copy the following into step03/application.py:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    from wsgiref.simple_server import make_server
    
    from pyramid.config import Configurator
    
    def main():
        config = Configurator()
        config.scan("views")
        app = config.make_wsgi_app()
        return app
    
    if __name__ == '__main__':
        app = main()
        server = make_server('0.0.0.0', 8080, app)
        server.serve_forever()
    
  4. Copy the following into step03/views.py:

    1
    2
    3
    4
    5
    from pyramid.view import view_config
    
    @view_config(renderer="hello.pt")
    def hello_view(request):
        return {"tutorial": "Little Dummy"}
    
  5. Copy the following into step03/hello.pt:

    1
    2
    3
    4
    5
    6
    7
    8
    <html>
    <head>
        <title>Hello</title>
    </head>
    <body>
    <p>Hello, ${tutorial}</p>
    </body>
    </html>
    
  6. Copy the following into step03/tests.py:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import unittest
    
    class ProjectorViewsUnitTests(unittest.TestCase):
        def test_hello_view(self):
            from views import hello_view
            result = hello_view({})
            self.assertEqual(result['tutorial'], 'Little Dummy')
    
    class ProjectorFunctionalTests(unittest.TestCase):
        def setUp(self):
            from application import main
            app = main()
            from webtest import TestApp
            self.testapp = TestApp(app)
    
        def test_it(self):
            res = self.testapp.get('/', status=200)
            self.assertTrue(b'Hello' in res.body)
    
  7. $ nosetests

    You should see the following output:

    ..
    ----------------------------------------------------------------
    Ran 2 tests in 0.885s
    
    OK
    
  8. $ python application.py

  9. Open http://127.0.0.1:8080 in your browser.

Extra Credit

  1. If you edit the template, do you have to restart to see your change?
  2. What other values are possible for renderer on @view_config?

Analysis

This step introduces code scanning. There are several different ways to do configuration in Pyramid: imperative (which we saw in Step 01: Hello World in Pyramid), scanning (common in many modern web frameworks), and our old friend ZCML. The choice is mainly one of style, though there are some sharp edges in some cases.

Note the coolness...all you have to do is return a dictionary in your view, and your template gets called on the way out the door, with that data.

Discussion

  • The history of configuration in Zope2, Zope3, BFG, then Pyramid
  • How things worked before renderers

Table Of Contents