创建一个 Pyramid 项目

正如我们看到的 创建您的第一个 Pyramid 应用 ,可以创建一个 Pyramid 完全手动应用。但是,使用我们的 cookiecutter 生成基本 Pyramid project .

项目是至少包含一个python的目录 package . 你会使用 Pyramid CookiCutter创建一个项目,您将在项目内部的包中创建应用程序逻辑。即使您的应用程序非常简单,也可以将驱动应用程序的代码放在包中,因为(1)包更容易用新代码扩展,(2)包中的应用程序也可以比不在包中的应用程序更容易分发。

塔架项目提供了 Pyramid 可用于生成项目的CookieCutter。我们的cookiecutter允许多个配置选项来生成您试图构建的应用程序类型。

使用 cookiecutter 可以安装的命令。

参见

也见 Cookiecutter Installation .

Pyramid 厨娘

塔架项目下发布的金字塔炊具提供以下配置选项:

所有配置选项都提供模板语言选项。

将URL映射到代码(路由)的配置取决于所选的后端选项,其他变化如下。

none

URL dispatch 路由选择

sqlalchemy

用于持久存储的sqlite, SQLAlchemy 对于ORM, URL dispatch 用于路由,以及 Alembic 用于数据库迁移

zodb

ZODB 用于永久存储和 traversal 路由选择

创建项目

安装 Pyramid ,您通过 venv 命令。我们称之为虚拟环境目录 env 并设置环境变量 VENV 走向它的道路。

我们假设你 previously installed cookiecutter ,遵循其安装说明。

当我们调用 cookiecutter ,它将创建一个表示项目的目录。

我们假设我们当前的工作目录是 VENV .

在所有平台上,使用cookiecutter生成一个项目。

cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout main

If prompted for the first item, accept the default yes 按回车键。

You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.
Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: myproject
repo_name [myproject]: myproject
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 1

然后我们运行以下命令。

在UNIX上:

# Reset our environment variable for a new virtual environment.
export VENV=~/env/myproject/env
# Change directory into your newly created project.
cd myproject
# Create a new virtual environment...
python3 -m venv $VENV
# ...where we upgrade packaging tools.
$VENV/bin/pip install --upgrade pip setuptools

或在Windows上:

# Reset our environment variable for a new virtual environment.
set VENV=c:\env\myproject\env
# Change directory into your newly created project.
cd myproject
# Create a new virtual environment...
python -m venv %VENV%
# ...where we upgrade packaging tools.
%VENV%\Scripts\pip install --upgrade pip setuptools

由于调用 cookiecutter 命令,一个名为 myproject 创建。那个目录是 project 目录。这个 setup.py 该目录中的文件可用于分发应用程序,或安装应用程序进行部署或开发。

.ini 文件命名 development.ini 将在项目目录中创建。你要用这个 .ini 用于配置服务器、运行应用程序和调试应用程序的文件。它包含启用交互式调试器和 settings 为发展而优化。

另一 .ini 文件命名 production.ini 也将在项目目录中创建。它包含禁用任何交互式调试器的配置(以防止不适当的访问和泄漏),并关闭许多调试设置。您可以使用此文件将应用程序投入生产。

这个 myproject 项目目录包含名为 myproject 代表一条 Python package 这很简单 Pyramid 示例代码。在这里您将编辑应用程序的python代码和模板。

我们在虚拟环境目录旁边的目录中创建了这个项目。但是,请注意,这不是强制性的。项目目录可以或多或少地放到文件系统的任何地方。您不需要将它放在一个特殊的“Web服务器”目录中。您可以将它放在虚拟环境目录中。作者主要使用Linux,并倾向于将他创建的项目目录放在 ~/projects 目录。在Windows上,最好将项目目录放在不包含空格字符的目录中,这样做是明智的。 避免 包含,即, My Documents . 因此,作者在使用Windows时,只需将项目放入 C:\projects .

警告

你需要避免使用 cookiecutter 创建与Python标准库组件同名的项目。特别是,这意味着您应该避免使用这些名称 sitetest ,两者都与Python标准库包冲突。你也应该避免使用这个名字 pyramid 这将与金字塔本身发生冲突。

安装新创建的用于开发的项目

要安装新创建的用于开发的项目,您应该 cd 到新创建的项目目录,并使用来自 virtual environment 创建时间: 安装 Pyramid 调用命令 pip install -e . ,以开发模式安装项目 (-e 用于“可编辑”)进入当前目录 (.

命名文件 setup.py 将在cookiecutter生成的项目目录的根目录中。这个 python 你在召唤的应该是生活在 bin (或) Scripts 在Windows上)虚拟python环境的目录。您终端的当前工作目录 must 是新创建的项目目录。

在UNIX上:

$VENV/bin/pip install -e .

或在Windows上:

%VENV%\Scripts\pip install -e .

在Unix上运行此命令的已删除输出如下所示:

Running setup.py develop for myproject
Successfully installed Jinja2-2.11.2 Mako-1.1.3 MarkupSafe-1.1.1 PasteDeploy-2.1.1 Pygments-2.7.3 hupper-1.10.2 myproject plaster-1.0 plaster-pastedeploy-0.7 pyramid-1.10.5 pyramid-debugtoolbar-4.9 pyramid-jinja2-2.8 pyramid-mako-1.1.0 repoze.lru-0.7 translationstring-1.4 venusian-3.0.0 waitress-1.4.4 webob-1.8.6 zope.deprecation-4.4.0 zope.interface-5.2.0

这将安装一个 distribution 将项目表示为虚拟环境解释器的库集,以便 import 语句和其他控制台脚本,如 pservepshellproutespviews .

为应用程序运行测试

要为应用程序运行单元测试,必须首先安装测试依赖项。

在UNIX上:

$VENV/bin/pip install -e ".[testing]"

在Windows上:

%VENV%\Scripts\pip install -e ".[testing]"

一旦安装了测试需求,就可以使用 pytest 刚安装在 bin 虚拟环境的目录。

在UNIX上:

$VENV/bin/pytest -q

在Windows上:

%VENV%\Scripts\pytest -q

以下是在Unix上运行测试的示例输出:

$VENV/bin/pytest -q
....
4 passed in 0.31s

测试本身在 tests 在您的 cookiecutter -生成的项目。在这个由 pyramid-cookiecutter-starter cookiecutter,只有几个样本测试存在。

备注

这个 -q 选项传递给 pytest 命令将输出限制为点流。如果你不通过 -q 您将看到详细的测试结果输出(这通常不是很有用)。

或者,如果您希望看到测试覆盖率,请通过 --cov 选择权 pytest

$VENV/bin/pytest --cov -q

cookiecutters包括的配置默认值 pytest 测试覆盖率。这些配置文件是 pytest.ini.coveragerc ,位于包的根目录。如果没有这些默认值,我们将需要指定要在其上运行测试和覆盖率的模块的路径。

$VENV/bin/pytest --cov=myproject myproject tests -q

参见

pytest 的文档 How to invoke pytest 或调用 pytest -h 查看它的全部选项。

运行项目应用程序

参见

另见输出 pserve --help .

一旦为开发安装了项目,就可以使用 pserve 针对生成的配置文件的命令。在我们的例子中,这个文件名为 development.ini .

在UNIX上:

$VENV/bin/pserve development.ini

在Windows上:

%VENV%\Scripts\pserve development.ini

以下是运行 pserve 在UNIX上:

$VENV/bin/pserve development.ini
Starting server in PID 77171.
Serving on http://localhost:6543
Serving on http://localhost:6543

访问受到限制,只有运行在与金字塔相同机器上的浏览器才能访问金字塔应用程序。但是,如果要打开对同一网络上其他计算机的访问,请编辑 development.ini 文件,并替换 listen 价值在 [server:main] 节,将其从 localhost:6543*:6543 (这相当于 0.0.0.0:6543 [::]:6543 )例如:

[server:main]
use = egg:waitress#main
listen = *:6543

现在当你使用 pserve 要启动应用程序,它将响应上的请求 all 您的系统拥有的IP地址,而不仅仅是请求 localhost . 这就是 0.0.0.0 在里面 serving on http://0.0.0.0:6543 手段。服务器将响应对 127.0.0.1 以及任何外部IP地址。例如,您的系统可能被配置为具有外部IP地址 192.168.1.50 . 如果是这样的话,如果你使用一个与金字塔运行在同一系统上的浏览器,它将能够通过 http://127.0.0.1:6543/ 以及通过 http://192.168.1.50:6543/ . 然而, 其他人 在同一网络上的其他计算机上,也可以通过访问访问访问浏览器中的金字塔应用程序。 http://192.168.1.50:6543/ . 如果使用ipv6,情况也是如此。 [::] 意思与 0.0.0.0 但是对于ipv6协议。

您可以更改服务器运行的端口,方法是更改 development.ini 文件。例如,您可以更改 listen = localhost:6543 线在 development.ini 文件的 [server:main] 截面至 listen = localhost:8080 在端口8080而不是端口6543上运行服务器。

您可以通过按关闭以这种方式启动的服务器 Ctrl-C (或) Ctrl-Break 在Windows上)。

当从cookiecutter创建项目时,用于运行金字塔应用程序的默认服务器命名为 Waitress . 这个服务器就是打印 Serving on... 运行时排队 pserve . 在开发过程中使用这个服务器是个好主意,因为它非常简单。它也可以用于轻型生产。在默认服务器下完成一些开发工作之前,不建议在其他服务器下设置应用程序,特别是在您还没有使用PythonWeb开发经验的情况下。python web服务器的设置可能很复杂,在试图优化它或使它“更像生产”之前,您应该对应用程序在默认环境中工作有一定的信心。在几个小时内尝试设置一个非默认服务器,而实际上却没有开始进行任何开发,这非常容易被偏离轨道。关于python web服务器的一个好处是它们在很大程度上是可互换的,所以如果您的应用程序在默认服务器下工作,那么如果您最终选择使用不同的服务器,它几乎肯定会在生产中的任何其他服务器下工作。现在别担心。

有关启动过程的详细信息,请参阅 启动 . 有关影响启动和运行时行为的环境变量和配置文件设置的详细信息,请参阅 环境变量和 .ini 文件设置 .

再装入代码

在开发过程中,运行 pserve 利用其 --reload 选择权。什么时候? --reload 传递给 pserve ,对项目使用的任何python模块的更改都将导致服务器重新启动。这通常使开发更容易,因为在 Pyramid 在服务器重新启动之前,应用程序不会生效。

例如,在UNIX上:

$VENV/bin/pserve development.ini --reload
Starting monitor for PID 36224.
Starting server in PID 36224.
Serving on http://localhost:6543
Serving on http://localhost:6543

现在,如果您对任何项目的 .py 文件或 .ini 文件,您将看到服务器自动重新启动:

/file-path-to/myproject/development.ini changed; reloading ...
Gracefully killing the server.
Starting monitor for PID 36286.
Starting server in PID 36286.
Serving on http://localhost:6543
Serving on http://localhost:6543

对模板文件的更改(例如 .pt.mak 文件)不会导致服务器重新启动。对模板文件的更改不需要重新启动服务器,只要 pyramid.reload_templates 设置在 development.ini 文件是 true . 当此设置为 true 将在不重新启动服务器的情况下立即生效。

查看应用程序

一旦您的应用程序运行通过 pserve 你可以参观一下 http://localhost:6543/ 在您的浏览器中。您将在浏览器中看到以下图像中显示的内容:

../_images/project.png

这是访问未修改的 cookiecutter 生成 pyramid-cookiecutter-starter 浏览器中的应用程序。

调试工具栏

../_images/project-show-toolbar.png

如果你点击 Pyramid logo位于页面右上角,将打开一个新的目标窗口,显示一个调试工具栏,在您开发时提供各种细节。此徽标将浮动在 Pyramid 当您开发一个应用程序时,并允许您根据需要显示工具栏。

../_images/project-debug.png

If you don't see the Pyramid logo on the top right of the page, it means you're browsing from a system that does not have debugging access. By default, for security reasons, only a browser originating from localhost (127.0.0.1) can see the debug toolbar. To allow your browser on a remote system to access the server, add a line within the [app:main] section of the development.ini file in the form debugtoolbar.hosts = X.X.X.X. For example, if your Pyramid application is running on a remote system, and you're browsing from a host with the IP address 192.168.1.1, you'd add something like this to enable the toolbar when your system contacts Pyramid:

[app:main]
# ... other settings ...
debugtoolbar.hosts = 192.168.1.1

有关调试工具栏允许您执行的操作的详细信息,请参阅 documentation for pyramid_debugtoolbar .

当您使用 production.ini 文件而不是 development.ini 运行应用程序的ini文件。

您还可以通过编辑来关闭调试工具栏。 development.ini 并发表评论。例如,而不是:

1[app:main]
2# ... elided configuration
3pyramid.includes =
4    pyramid_debugtoolbar

pyramid_debugtoolbar 线:

1[app:main]
2# ... elided configuration
3pyramid.includes =
4#    pyramid_debugtoolbar

然后重新启动应用程序以查看工具栏是否已关闭。

请注意,如果您对 pyramid_debugtoolbar 线 # must 在第一列。如果您将它放在其他地方,然后尝试重新启动应用程序,您将收到一个以如下方式结束的错误:

ImportError: No module named #pyramid_debugtoolbar

项目结构

这个 pyramid-cookiecutter-starter CookiCutter生成了一个 project (命名) myproject ,其中包含一条 Python package . 包装是 also 已命名 myproject ;cookiecutter生成一个包含共享其名称的包的项目。

所有 Pyramid cookiecutter -生成的项目具有相似的结构。这个 myproject 我们生成的项目具有以下目录结构:

myproject
├── .coveragerc
├── .gitignore
├── CHANGES.txt
├── MANIFEST.in
├── README.txt
├── development.ini
├── myproject
│   ├── __init__.py
│   ├── routes.py
│   ├── static
│   │   ├── pyramid-16x16.png
│   │   ├── pyramid.png
│   │   └── theme.css
│   ├── templates
│   │   ├── 404.jinja2
│   │   ├── layout.jinja2
│   │   └── mytemplate.jinja2
│   └── views
│       ├── __init__.py
│       ├── default.py
│       └── notfound.py
├── production.ini
├── pytest.ini
├── setup.py
├── testing.ini
└── tests
    ├── __init__.py
    ├── conftest.py
    ├── test_functional.py
    └── test_views.py

tests 套餐

这个 conftest.pytest_functional.pytest_views.py 中的模块 tests 包中包含应用程序的测试。

 1import os
 2from pyramid.paster import get_appsettings
 3from pyramid.scripting import prepare
 4from pyramid.testing import DummyRequest, testConfig
 5import pytest
 6import webtest
 7
 8from myproject import main
 9
10
11def pytest_addoption(parser):
12    parser.addoption('--ini', action='store', metavar='INI_FILE')
13
14@pytest.fixture(scope='session')
15def ini_file(request):
16    # potentially grab this path from a pytest option
17    return os.path.abspath(request.config.option.ini or 'testing.ini')
18
19@pytest.fixture(scope='session')
20def app_settings(ini_file):
21    return get_appsettings(ini_file)
22
23@pytest.fixture(scope='session')
24def app(app_settings):
25    return main({}, **app_settings)
26
27@pytest.fixture
28def testapp(app):
29    testapp = webtest.TestApp(app, extra_environ={
30        'HTTP_HOST': 'example.com',
31    })
32
33    return testapp
34
35@pytest.fixture
36def app_request(app):
37    """
38    A real request.
39
40    This request is almost identical to a real request but it has some
41    drawbacks in tests as it's harder to mock data and is heavier.
42
43    """
44    with prepare(registry=app.registry) as env:
45        request = env['request']
46        request.host = 'example.com'
47        yield request
48
49@pytest.fixture
50def dummy_request():
51    """
52    A lightweight dummy request.
53
54    This request is ultra-lightweight and should be used only when the request
55    itself is not a large focus in the call-stack.  It is much easier to mock
56    and control side-effects using this object, however:
57
58    - It does not have request extensions applied.
59    - Threadlocals are not properly pushed.
60
61    """
62    request = DummyRequest()
63    request.host = 'example.com'
64
65    return request
66
67@pytest.fixture
68def dummy_config(dummy_request):
69    """
70    A dummy :class:`pyramid.config.Configurator` object.  This allows for
71    mock configuration, including configuration for ``dummy_request``, as well
72    as pushing the appropriate threadlocals.
73
74    """
75    with testConfig(request=dummy_request) as config:
76        yield config
1def test_root(testapp):
2    res = testapp.get('/', status=200)
3    assert b'Pyramid' in res.body
4
5def test_notfound(testapp):
6    res = testapp.get('/badurl', status=404)
7    assert res.status_code == 404
 1from myproject.views.default import my_view
 2from myproject.views.notfound import notfound_view
 3
 4
 5def test_my_view(app_request):
 6    info = my_view(app_request)
 7    assert app_request.response.status_int == 200
 8    assert info['project'] == 'myproject'
 9
10def test_notfound_view(app_request):
11    info = notfound_view(app_request)
12    assert app_request.response.status_int == 404
13    assert info == {}

样品 conftest.py 配置和文件包含fixture。样品 test_functional.py 文件中定义了两个功能测试。样品 test_views.py 文件中定义了两个单元测试。这些测试在运行时执行 pytest -q . 在构建应用程序时,可以在此处添加更多测试。您不需要编写要使用的测试 Pyramid . 提供这些文件只是为了方便和举例。

单元、集成和功能测试 关于写作的更多信息 Pyramid 单元测试。

这个 myproject Project

这个 myproject project 目录是应用程序的分发和部署包装。它包含两个 myproject package 表示应用程序以及用于描述、运行和测试应用程序的文件。

  1. .coveragerc 配置运行测试时的覆盖率。

  2. .gitignore 告诉Git从源代码版本控制中忽略哪些文件和目录。

  3. CHANGES.txt 描述您对应用程序所做的更改。它是按惯例写的 reStructuredText 格式。

  4. MANIFEST.in 是一个 distutils “manifest”文件,命名包的源分发中应包含哪些文件 python setup.py sdist 运行。

  5. README.txt 一般描述应用程序。它是按惯例写的 reStructuredText 格式。

  6. development.ini 是一个 PasteDeploy 可用于在开发期间执行应用程序的配置文件。

  7. production.ini 是一个 PasteDeploy 可用于在生产配置中执行应用程序的配置文件。

  8. pytest.ini 是用于运行测试的配置文件。

  9. setup.py 是用于测试和分发应用程序的文件。这是一个标准 Setuptools setup.py 文件。

  10. testing.ini 是一个 PasteDeploy 可用于执行应用程序测试的配置文件。

  11. tests 包含应用程序的单元和功能测试代码的包。

development.ini

这个 development.ini 文件是 PasteDeploy 配置文件。其目的是指定在调用时要运行的应用程序 pserve 以及提供给该应用程序的部署设置。

生成的 development.ini 文件如下:

 1###
 2# app configuration
 3# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
 4###
 5
 6[app:main]
 7use = egg:myproject
 8
 9pyramid.reload_templates = true
10pyramid.debug_authorization = false
11pyramid.debug_notfound = false
12pyramid.debug_routematch = false
13pyramid.default_locale_name = en
14pyramid.includes =
15    pyramid_debugtoolbar
16
17# By default, the toolbar only appears for clients from IP addresses
18# '127.0.0.1' and '::1'.
19# debugtoolbar.hosts = 127.0.0.1 ::1
20
21###
22# wsgi server configuration
23###
24
25[server:main]
26use = egg:waitress#main
27listen = localhost:6543
28
29###
30# logging configuration
31# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
32###
33
34[loggers]
35keys = root, myproject
36
37[handlers]
38keys = console
39
40[formatters]
41keys = generic
42
43[logger_root]
44level = INFO
45handlers = console
46
47[logger_myproject]
48level = DEBUG
49handlers =
50qualname = myproject
51
52[handler_console]
53class = StreamHandler
54args = (sys.stderr,)
55level = NOTSET
56formatter = generic
57
58[formatter_generic]
59format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s

此文件包含几个部分,包括 [app:main][server:main] 以及与日志配置相关的其他几个部分。

这个 [app:main] 部分表示您的 Pyramid 应用。这个 use 设置是在 [app:main] 部分。它的默认值, egg:myproject ,指示我们的MyProject项目包含应提供服务的应用程序。添加到此节的其他设置将作为关键字参数传递给名为 main 在我们的包裹里 __init__.py 模块。通过向该部分添加更多设置,可以向应用程序提供启动时间配置参数。

参见

入口点和PasteDeploy .ini 文件夹 有关 use = egg:myproject 此部分中的值。

这个 pyramid.reload_templates 设置在 [app:main] 截面是 Pyramid -传入框架的特定设置。如果它存在,它的值是 true ,支持的模板更改将不需要检测到应用程序重新启动。见 自动重新加载模板 更多信息。

警告

这个 pyramid.reload_templates 对于生产应用程序,应关闭选项,因为打开模板时,模板呈现速度会减慢。

这个 pyramid.includes 设置在 [app:main] 部分告诉金字塔从另一个包“包括”配置。在这种情况下, pyramid.includes = pyramid_debugtoolbar 告诉金字塔包含来自 pyramid_debugtoolbar 包裹。这将在开发模式下打开调试面板,可通过单击打开该面板。 Pyramid 屏幕右上角的徽标。包含调试工具栏还可以在发生错误时交互式调试异常。

本节中可能存在各种其他设置,这些设置与调试或影响 Pyramid 应用。见 环境变量和 .ini 文件设置 有关这些设置的详细信息。

名字 main 在里面 [app:main] 表示这是由运行的默认应用程序 pserve 当针对该配置文件调用它时。名字 main 是PasteDeploy使用的约定,表示它是默认应用程序。

这个 [server:main] 配置文件的部分配置在TCP端口6543上侦听的wsgi服务器。它被配置为只在本地主机上侦听 (127.0.0.1

后面的部分 # logging configuration 表示python的标准库 logging 应用程序的模块配置。默认配置将应用程序日志记录输出发送到终端的标准错误输出。有关详细信息,请参阅 登录 .

PasteDeploy 有关您可以放入其中的其他类型内容的详细信息,请参阅文档。 .ini 文件,如其他应用程序, middleware 交替 WSGI 服务器实现。

production.ini

这个 production.ini 文件是 PasteDeploy 配置文件的用途与 development.ini . 但是,它禁用调试工具栏,并筛选除警告级别以上的日志消息以外的所有日志消息。它还关闭模板开发选项,这样在更改模板时不会自动重新加载模板,并关闭所有调试选项。此文件适合使用,而不是 development.ini 当您将应用程序投入生产时。

使用它很重要 production.ini (和 not development.ini )对应用程序进行基准测试并将其投入生产。 development.ini 使用调试工具栏配置系统,该工具栏有助于开发,但包含此工具栏会将页面呈现时间降低一个数量级以上。如果配置不正确,调试工具栏也是一个潜在的安全风险。

testing.ini

这个 testing.ini 文件是 PasteDeploy 配置文件的用途与 development.ini . 它类似于 development.ini ,但经过优化以减少测试执行时间。它禁用调试工具栏和模板的自动重新加载,因为这会减慢测试执行速度。此文件适用于代替 development.ini 当您运行应用程序的测试时。

MANIFEST.in

这个 MANIFEST.in 文件是 distutils 配置文件,指定在 distribution 在运行时创建金字塔项目的 python setup.py sdist . 由于默认值中包含的信息 MANIFEST.in ,金字塔项目的列表将包括 .txt 文件夹, .ini 文件夹, .rst 文件、图形文件和模板文件,以及 .py 文件夹。请参阅Python打包权威的Python打包用户指南 Including files in source distributions with MANIFEST.in 有关的语法和用法的详细信息 MANIFEST.in .

不存在 MANIFEST.in 文件或不将源代码签入版本控制存储库, setup.py sdist 仅限地点 python源文件 (文件结尾为 .py 扩展)到由 python setup.py sdist . 这意味着,例如,如果您的项目没有签入与SetupTools兼容的源代码管理系统,并且您的项目目录没有包含 MANIFEST.in 文件告诉 sdist 机械包括 *.pt 文件 myproject/templates/mytemplate.pt 文件不会包含在生成的tarball中。

金字塔炊事员生成的项目包括默认 MANIFEST.in 文件。这个 MANIFEST.in 文件包含的声明告诉它包含类似 *.pt*.css*.js 在生成的tarball中。如果包含扩展名不是项目的 MANIFEST.in 如果不使用与安装工具兼容的版本控制系统,则需要编辑 MANIFEST.in 归档并包含包含新文件所需的语句。在前面提到的《Python打包用户指南》中,请参见 MANIFEST.in commands 有关如何执行此操作的详细信息。

您也可以删除 MANIFEST.in 从你的项目中 Setuptools 一种功能,只需将检入版本控制系统的所有文件放入生成的tarball中即可。要实现这一点,请将您希望与应用程序的python文件一起分发的所有文件检查到Subversion中。在你这样做之后,当你重新运行 setup.py sdist ,签入版本控制系统的所有文件将包含在tarball中。如果不使用Subversion,而是使用其他版本控制系统,则可能需要安装 Setuptools 附加如 setuptools-gitsetuptools-hg 以使此行为正常工作。

setup.py

这个 setup.py 文件是 Setuptools 安装文件。它用于定义安装包和测试依赖项以及分发应用程序的需求。

备注

setup.py 实际上是Python开发人员用来分发可重用代码的标准。你可以阅读更多关于 setup.py 文件及其在 Python Packaging User GuideSetuptools documentation .

我们生成的 setup.py 如下所示:

 1import os
 2
 3from setuptools import setup, find_packages
 4
 5here = os.path.abspath(os.path.dirname(__file__))
 6with open(os.path.join(here, 'README.txt')) as f:
 7    README = f.read()
 8with open(os.path.join(here, 'CHANGES.txt')) as f:
 9    CHANGES = f.read()
10
11requires = [
12    'plaster_pastedeploy',
13    'pyramid',
14    'pyramid_jinja2',
15    'pyramid_debugtoolbar',
16    'waitress',
17]
18
19tests_require = [
20    'WebTest',
21    'pytest',
22    'pytest-cov',
23]
24
25setup(
26    name='myproject',
27    version='0.0',
28    description='myproject',
29    long_description=README + '\n\n' + CHANGES,
30    classifiers=[
31        'Programming Language :: Python',
32        'Framework :: Pyramid',
33        'Topic :: Internet :: WWW/HTTP',
34        'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
35    ],
36    author='',
37    author_email='',
38    url='',
39    keywords='web pyramid pylons',
40    packages=find_packages(exclude=['tests']),
41    include_package_data=True,
42    zip_safe=False,
43    extras_require={
44        'testing': tests_require,
45    },
46    install_requires=requires,
47    entry_points={
48        'paste.app_factory': [
49            'main = myproject:main',
50        ],
51    },
52)

这个 setup.py 文件调用 Setuptools setup 函数,根据传递给 pip 在命令行上。

在该函数调用的参数中,保存有关应用程序的信息。尽管这超出了本文档的范围,但要解释有关 Setuptools 设置文件,我们将提供本节中此文件中存在的内容的旋风式教程。

应用程序的名称可以是任何字符串;它在 name 字段。版本号在 version 价值。简要说明见 description 字段。这个 long_description 通常是 READMECHANGES 附加在一起的文件。这个 classifiers 字段是 Trove classifiers 描述您的应用程序。 authorauthor_email 是可能不需要任何描述的文本字段。 url 应该指向应用程序项目的URL(如果有)的字段。 keywords 是描述您的项目的关键字。 packages=find_packages(exclude=['tests']) 使打包应用程序时找到项目中的所有包。 include_package_data 如果将这些文件签入版本控制,则在打包应用程序时将包括非python文件。 zip_safe=False 表示此包作为压缩鸡蛋使用不安全;相反,它将始终作为目录解包,这更方便。 extras_require 是一个Python字典,它定义运行测试所需安装的内容。 install_requires 指示此包依赖于 pyramid 包裹。我们检查了 entry_points 在我们的讨论中 development.ini 文件;此文件定义 main 表示项目应用程序的入口点。

通常你只需要考虑 setup.py 当将应用程序分发给其他人、添加python包依赖项或为自己的使用对应用程序进行版本控制时,文件。为了好玩,您现在可以尝试以下命令:

$VENV/bin/python setup.py sdist

这将在 dist 名为的子目录 myproject-0.0.tar.gz . 你可以把这个tarball发送给其他想要安装和使用你的应用程序的人。

这个 myproject Package

这个 myproject package 住在里面 myproject project . 它包含:

  1. __init__.py 文件表示这是一个python package . 它还包含帮助用户运行应用程序的代码,包括 main 用作命令入口点的函数,例如 pservepshellpviews 以及其他。

  2. A templates 目录,其中包含 Jinja2 (或其他类型)模板。

  3. A routes.py 模块,其中包含应用程序的路由代码。

  4. A views 包,其中包含应用程序的视图代码。

  5. A static 目录,其中包含静态文件,包括图像和CSS。

这些纯粹是厨师制定的惯例。 Pyramid 不要坚持用任何特殊的方式命名事物。然而,遵循金字塔标准来命名通常是个好主意,这样其他金字塔开发人员就可以在需要帮助时快速地了解您的代码。

__init__.py

我们需要一个小的python模块来配置我们的应用程序,并为我们的 PasteDeploy .ini 文件。这是名为 __init__.py . 存在 __init__.py 同时通知python包含它的目录是 包裹 .

 1from pyramid.config import Configurator
 2
 3
 4def main(global_config, **settings):
 5    """ This function returns a Pyramid WSGI application.
 6    """
 7    with Configurator(settings=settings) as config:
 8        config.include('pyramid_jinja2')
 9        config.include('.routes')
10        config.scan()
11    return config.make_wsgi_app()
  1. 第1行导入 Configurator 类从 pyramid.config 我们以后会用到的。

  2. 第4-11行定义了一个名为 main 返回一个 Pyramid WSGi应用程序。此函数将由 PasteDeploy 运行后的框架 pserve .

    这个 main 函数配置应用程序。

    第7行打开一个上下文管理器,其中包含 Configurator .

    第8行添加了对jinja2模板绑定的支持,允许我们使用 .jinja2 延伸。

    第9行包括 routes.py 模块。

    第10行调用 config.scan() ,它获取包中其他位置声明的视图注册(在本例中,在 views.py 模块)。

    第11行返回 WSGI 应用于函数调用方(金字塔的pserver)。

参见

启动过程 有关应用程序的详细信息 settingsmainarguments 和陈述。

routes.py

这个 routes.py 模块包含在 main 在我们的功能 __init__.py . 它注册一个视图和一个路由。

1def includeme(config):
2    config.add_static_view('static', 'static', cache_max_age=3600)
3    config.add_route('home', '/')

第2行注册一个静态视图,它将从 myproject:static asset specification (the static 目录 myproject 包装)。

第3行增加了 route 到配置。此路由稍后由中的视图使用 views 模块。

views 包裹

在一个 Pyramid 应用程序由 查看可调用 . 一 view callable 是一个 Pyramid Web应用程序开发人员;它是接受 request 它返回一个 response .

我们的项目有一个 views 包,因为它是包含 __init__.py 文件。这个 __init__.py 文件碰巧没有内容,尽管它可以作为一个项目开发。

我们有两个视图模块 views 包裹。让我们来看一看 default.py .

1from pyramid.view import view_config
2
3
4@view_config(route_name='home', renderer='myproject:templates/mytemplate.jinja2')
5def my_view(request):
6    return {'project': 'myproject'}

第4-6行定义并注册A view callable 已命名 my_view. The function named my_view is decorated with a view_config decorator (which is processed by the config.scan() line in our __init__.py). The view_config decorator asserts that this view be found when a route named home is matched. In our case, because our routes.py maps the route named home to the URL pattern /, this route will match when a visitor visits the root URL. The view_config decorator also names a `` 呈现器``,在本例中,它是一个模板,将用于呈现可调用视图的结果。此特定视图声明指向 myproject:templates/mytemplate.jinja2 ,这是一个 asset specification 它指定了 mytemplate.jinja2 文件内 templates 目录 myproject 包裹。还有第二种形式的资产规范:相对资产规范。在某些情况下,可以在包的名称中省略“在某些情况下,可以省略包的绝对名称”。例如,您可以使用 ../templates/mytemplate.jinja2 . 指向的模板文件是 Jinja2 模板文件 (templates/mytemplate.jinja2

这个视图可调用函数被传递一条信息: request . 这个 请求 是的实例 WebOb Request 类,表示浏览器对服务器的请求。

此视图配置为调用 renderer 在模板上。视图返回的字典(第6行)提供了生成HTML时呈现器替换到模板中的值。然后,渲染器返回 response .

备注

字典提供的值 template S

现在让我们看看 notfound.py .

1from pyramid.view import notfound_view_config
2
3
4@notfound_view_config(renderer='myproject:templates/404.jinja2')
5def notfound_view(request):
6    request.response.status = 404
7    return {}

此文件类似于 default.py . 它只返回一个 404 对模板的响应状态和空字典位于 myproject:templates/404.jinja2 .

备注

当应用程序与cookiecutter一起运行时 default development.ini 配置, logging is set up 帮助调试。如果引发异常,则在 the console running the server . 阿尔索 print() 语句可以插入到应用程序中进行调试,以便将输出发送到此控制台。

备注

development.ini 具有控制如何重新加载模板的设置, pyramid.reload_templates .

  • 当设置为 True (就像在厨房里一样) development.ini ,更改后的模板将自动重新加载,而无需重新启动服务器。这在开发时很方便,但会降低模板渲染速度。

  • 当设置为 False (默认值),更改模板需要重新启动服务器才能重新加载模板。生产应用程序应使用 pyramid.reload_templates = False .

参见

也见 正在写入使用渲染器的视图可调用文件 有关视图、渲染器和模板如何关联和协作的详细信息。

参见

金字塔还可以动态重新加载更改后的python文件。也见 再装入代码 .

参见

也见 调试工具栏 它提供了对应用程序内部的交互访问,并且,如果发生异常,允许交互访问从Python解释器返回的执行堆栈帧。

static

此目录包含支持 layout.jinja2 模板。它包括CSS和图像。

templates/layout.jinja2

这是基本布局内容。它包含内容块的单个标记。其他模板继承其内容,为Web应用程序提供布局。它的内容太长,无法在此显示,但这里有一个摘录:

34          <div class="col-md-10">
35            {% block content %}
36                <p>No content</p>
37            {% endblock content %}
38          </div>

templates/mytemplate.jinja2

这是内容 Jinja2 项目中存在的模板。它被调用引用 @view_config 作为 renderermy_view 在中查看可调用 views/default.py 文件。见 正在写入使用渲染器的视图可调用文件 有关渲染器的详细信息。它继承(“扩展”)所提供的HTML layout.jinja2 ,将内容块替换为其自己的内容。

1{% extends "layout.jinja2" %}
2
3{% block content %}
4<div class="content">
5  <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter project</span></h1>
6  <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
7</div>
8{% endblock content %}

模板由视图配置访问和使用,有时由视图函数本身访问和使用。见 直接使用模板通过配置用作呈现器的模板 .

templates/404.jinja2

此模板类似于 mytemplate.jinja2 但是有一些不同。它被调用引用 @notfound_view_config 作为 renderernotfound_view 在中查看可调用 views/notfound.py 文件。它继承了由提供的HTML layout.jinja2 ,将内容块替换为其自己的内容。

1{% extends "layout.jinja2" %}
2
3{% block content %}
4<div class="content">
5  <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter project</span></h1>
6  <p class="lead"><span class="font-semi-bold">404</span> Page Not Found</p>
7</div>
8{% endblock content %}

修改包结构

对于您的应用程序的代码布局来说,最好不要过分偏离可接受的金字塔cookiecutter默认值。如果您不经常改变事情,其他金字塔编码器将能够更快地理解您的应用程序。然而,Cookiecutter为您所做的代码布局选择绝不是不可思议的或必需的。尽管任何Cookiecutter都为您做出了选择,但是您可以决定以任何您认为合适的方式来布局代码。

例如,名为 add_view() 要求您通过 dotted Python name 或直接对象引用,作为要用作视图的类或函数。默认情况下, starter CookiCutter会让你创建一个 views 目录,并为每个视图或相关视图集合添加一个文件。但是,创建一个 views.py 在包中进行模块化,并向其中添加视图函数。

无论您喜欢什么结构,只要您使用 @view_config 与一起注册视图的指令 config.scan() ,它们将在应用程序重新启动时自动提取。

使用交互式shell

可以使用 pshell 命令加载具有类似配置的python解释器提示,如果通过 pserve . 这是一个有用的调试工具。见 pshell :交互式Shell 了解更多详细信息。

这是什么 pserve 事情

由a生成的代码 Pyramid cookiecutter假定您将使用 pserve 命令在进行开发时启动应用程序。 pserve 是一个读取 PasteDeploy .ini 文件(例如, development.ini ,并将服务器配置为 Pyramid 基于文件中数据的应用程序。

pserve 决不是唯一的启动和服务 Pyramid 应用。正如我们看到的 创建您的第一个 Pyramid 应用pserve 根本不需要调用来运行 Pyramid 应用。使用 pserve 运行一个 Pyramid 应用程序是纯常规的,基于它的CookieCutter的输出。但我们强烈建议使用 pserve 在开发应用程序时,因为许多其他方便的自省命令(例如 pviewsprequestproutes 以及其他)的配置可用性 .ini 文件格式。它还配置金字塔日志,并提供 --reload 切换以方便在代码更改时重新启动服务器。

使用备用wsgi服务器

金字塔炊事员生成使用 Waitress WSGI服务器。服务生是一个适合开发和轻生产使用的服务器。它既不是最快的,也不是最有特色的wsgi服务器。相反,它的主要功能是在金字塔需要运行的所有平台上工作,从金字塔的开发人员的角度来看,它是默认服务器的一个很好的选择。

任何wsgi服务器都可以运行 Pyramid 应用。但我们建议您坚持使用默认的服务器进行开发,并等待研究其他服务器选项,直到您准备好将应用程序部署到生产环境。除非出于某种原因需要在非本地系统上开发,否则在准备部署之前,研究备用服务器选项通常会分散您的注意力。但是我们建议在您完全控制的本地系统上使用默认配置进行开发;它将提供最佳的开发体验。

与默认的服务生服务器相比,一个流行的产品替代方案是 mod_wsgi . 你可以使用 mod_wsgi 为你服务 Pyramid 应用程序使用的是ApacheWeb服务器,而不是像服务生那样的任何“纯Python”服务器。它既快又有特点。见 运行一个 Pyramid 申请 mod_wsgi 有关详细信息。

另一个好的生产选择是 gunicorn 。它比女服务员更快,配置也比 mod_wsgi ,尽管在其默认配置中,它依赖于前面有一个缓冲HTTP代理。在撰写本文时,它不能在Windows上运行。

自动重新加载代码

在开发过程中,在进行更改时自动重新启动Web服务器非常有用。 pserve 有一个 --reload 切换以启用此功能。它使用 hupper 包以启用此行为。当代码崩溃时, hupper 将等待另一个更改或 SIGHUP 重新启动前发出信号。

肌力支持

默认情况下 hupper 将轮询文件系统以查看对所有Python代码的更改。在较大的项目中,这可能是非常低效的。为了更好地使用硬盘,您应该安装 watchmanwatchdog 正在开发包。 hupper 将使用,以效率优先顺序,如果可用, watchmanwatchdog ,或最后轮询以检测文件系统的更改。

监视自定义文件

默认情况下, pserve --reload 将监视所有导入的python代码(所有 sys.modules )以及传递给 pserve (例如, development.ini )你可以指导 pserve 通过定义 [pserve] 配置文件中的节。例如,假设您的应用程序加载 favicon.ico 启动时的文件,并将其存储在内存中,以有效地多次提供服务。当你改变它,你想要 pserve 重新启动:

[pserve]
watch_files =
    myproject/static/favicon.ico

路径可以是绝对路径,也可以是相对于配置文件的路径。它们也可能是 asset specification . 这些路径被传递到 hupper 它对全局搜索有一些基本支持。可接受的全局模式取决于所使用的Python版本。