Руководство: Pyramid для Людей — часть 4

в 7:04, , рубрики: pyramid, python, tutorial for humans, перевод pyramid доки, метки: , ,

Часть 3: юнит- и функциональное тестирование, Hello World в Chameleon

Шаг 04: Каркас представлений

Хватит с нас “hello world”, теперь приступим к работе над Projector'ом. UX-человек обычно имеет ряд представлений, которые нуждаются в прототипировании и отображении в URL-структуру.

Мы хотим сделать этот процесс быстрым и продуктивным.

В этом шаге мы копируем структуру карты сайта такую:
/
/about.html
/acme
/people
… и сделаем ряд URL'ов которые это осуществят. По ходу, мы создаем больше представлений и больше шаблонов.

Цели
  • Введение в UX рабочий процесс, для примера, используя произвольные данные
Что ожидается
  • “Стандартные” и “именованные” представления
  • Больше ZPT конструкций
Шаги

$ cd ../../creatingux; mkdir step04; cd step04

(Неизмененное) Копируем одно в другое — step04/application.py:

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()

Далее также здесь — step04/views.py:

from pyramid.view import view_config

@view_config(renderer="index.pt")
def index_view(request):
    return {}

@view_config(renderer="about.pt", name="about.html")
def about_view(request):
    return {}

@view_config(renderer="company.pt", name="acme")
def company_view(request):
    return {"company": COMPANY, "projects": PROJECTS}

@view_config(renderer="people.pt", name="people")
def people_view(request):
    return {"company": COMPANY, "people": PEOPLE}

# Dummy data
COMPANY = "ACME, Inc."

PEOPLE = [
        {'name''sstanton''title''Susan Stanton'},
        {'name''bbarker''title''Bob Barker'},
]

PROJECTS = [
        {'name''sillyslogans''title''Silly Slogans'},
        {'name''meaninglessmissions''title''Meaningless Missions'},
]

И здесь — step04/index.pt:

<html>
<head>
    <title>Projector - Home</title>
</head>
<body>
<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about.html">About Projector</a></li>
    <li><a href="/acme">ACME, Inc.</a></li>
    <li><a href="/people">People</a></li>
</ul>
<h1>Projector - Home</h1>
</body>
</html>

Дальше здесь — step04/about.pt:

<html>
<head>
    <title>Projector - About</title>
</head>
<body>
<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about.html">About Projector</a></li>
    <li><a href="/acme">ACME, Inc.</a></li>
    <li><a href="/people">People</a></li>
</ul>
<h1>Projector - About</h1>
<p>Projector is a simple project management tool capable of hosting
    multiple projects for multiple independent companies,
    sharing a developer pool between autonomous companies.</p>
</body>
</html>

Здесь — step04/company.pt:

<html>
<head>
    <title>Projector - People</title>
</head>
<body>
<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about.html">About Projector</a></li>
    <li><a href="/acme">ACME Inc.</a></li>
    <li><a href="/people">People</a></li>
</ul>
<h1>People</h1>
<ul>
    <li tal:repeat="person people">
        <a href="${person.name}">${person.title}</a>
    </li>
</ul>
</body>
</html>

И наконец, здесь — step04/tests.py:

import unittest

class ProjectorViewsUnitTests(unittest.TestCase):
    def test_hello_view(self):
        from views import index_view
        result = index_view({})
        self.assertEqual(len(result.keys()), 0)

    def test_about_view(self):
        from views import about_view
        result = about_view({})
        self.assertEqual(len(result.keys()), 0)

    def test_company_view(self):
        from views import company_view
        result = company_view({})
        self.assertEqual(result["company"], "ACME, Inc.")
        self.assertEqual(len(result["projects"]), 2)

    def test_people_view(self):
        from views import people_view
        result = people_view({})
        self.assertEqual(result["company"], "ACME, Inc.")
        self.assertEqual(len(result["people"]), 2)

class ProjectorFunctionalTests(unittest.TestCase):
    def setUp(self):
        from application import main
        app = main()
        from webtest import TestApp
        self.testapp = TestApp(app)

    def test_home(self):
        res = self.testapp.get('/', status=200)
        self.failUnless('Home' in res.body)

    def test_it(self):
        res = self.testapp.get('/', status=200)
        self.failUnless('Home' in res.body)
        res = self.testapp.get('/about.html', status=200)
        self.failUnless('autonomous' in res.body)
        res = self.testapp.get('/people', status=200)
        self.failUnless('Susan' in res.body)
        res = self.testapp.get('/acme', status=200)
        self.failUnless('Silly Slogans' in res.body)

Дальше пишем:
$ nosetests
что должно выдать нам отчет по 6ти тестам.
Запускаем приложение:
$ python application.py
И радуемся результату в браузере — 127.0.0.1:8080

Дополнительные вопросы

Что произойдет если у вас есть две регистрации представления без @ name атрибута, meaning both as the default?
Правда ли что Chameleon (сейчас, если мы говорим о второй версии) в любом случае лучше для предоставления вам сообщений об ошибках? Попробуйте это, положив немного ошибок в ваши Python выражения.
Будет ли WebTest корректно срабатывать на эти ошибки?
Влияет ли прибавление .html, к вашим URL'ам, на что-нибудь?

Анализ

Мы начали процесс построения пространства URL'ов, которые отображаются в объекты и иерархию, в нашем приложении. На данный момент, мы смоделировали это с использованием представлений.

Несмотря на увеличение количества наших тестов, каждый из них до сих пор очень маленький. Даже такой простой тест будет до сих пор ловить большинство глупых ошибок которые всплывают в процессе начальной разработки. Надеемся, вы найдете для себя nosetests'ы более продуктивными, чем простое кликание.

Тезисы

How do the registrations happen under the hood?
Chameleon, кэширование, и занесение готовых версий на диск

Шаг 05: Создание основного шаблона

Автор: ks_ks

Поделиться

* - обязательные к заполнению поля