summaryrefslogtreecommitdiff
path: root/docs/tutorials/lxmlgraph/step01.rst
blob: f44f48db9e754138af735b3bc84fb3afbe4805fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
================================================
Step 01: Non-XML Hello World for ``repoze.bfg``
================================================

Before we work on implementing an XML graph, we need a simple starting
point for a basic ``repoze.bfg`` application.  In this step we'll do
the least amount possible to run a ``repoze.bfg`` sample application.

.. note::

  All steps in this writeup presume that you have a virtualenv setup
  as shown in the Installation step.  More specifically: *make sure
  you are using that virtualenv's Python* !!

Directory Layout
====================

Each step in this writeup has a subdirectory for the working
application described in that step.  Thus, starting at this docs
directory, we have::

  docs/
    step01/
      myapp/
        __init__.py
      	configure.zcml
      	models.py
      	views.py
      run.py
    step02/
    step03/

Below we discuss each file in the ``step01``, then show how to run and
use the demo application.


Directory ``myapp``
---------------------

This directory contains the *package* to be published.  That's right,
I said *package*.  ``repoze.bfg``, as we will see in a moment, uses
Python packages as the unit of publishing.


Module ``myapp/__init__.py``
------------------------------

This is (usually-empty) file that makes a directory into a Python
"package."  For ``repoze.bfg`` this is particularly important


Module ``myapp/configure.zcml``
--------------------------------

Unlike other frameworks, ``repoze.bfg`` doesn't try to hide
configuration.  Instead, configuration using ZCML is the central
wiring point.  At the same time, ZCML is used in a very basic way, to
avoid confusion it can cause.

.. literalinclude:: step01/myapp/configure.zcml
   :linenos:
   :language: xml

#. Lines 1-3 provide the root node and namespaces for the
   configuration language.  ``bfg`` is the namespace for
   ``repoze.bfg``-specific configuration directives.

#. Line 5 initializes those ``repoze.bfg``-specific configuration
   directives.

#. Lines 8-11 register a single view for model objects that support
   the IMyModel interface.  In this case we made a default view, which
   means going to ``/a`` triggers the default view of instance ``a``.
   Finally, the ``view`` attribute points at a Python function that
   does all the work for this view.


Module ``myapp/models.py``
-----------------------------

In our sample app, the ``models.py`` module provides the model data.
We create an interface ``IMyModel`` that gives us the "type system"
for our data.  We then write a class ``MyModel`` that provides the
behavior for instances of the ``IMyModel`` type.

.. literalinclude:: step01/myapp/models.py
   :linenos:

#. Lines 5-6 define the interface.

#. Lines 8-11 provide a class for that interface.

#. Lines 13-15 make a small tree of sample data (``/a`` and ``/b`` for
   URLs.)

#. Line 17 is a function that will be grabbed by the server when it
   wants to find the top of the model.


Module ``myapp/views.py``
---------------------------

Much of the heavy liftin in a ``repoze.bfg`` application comes in the
views.  These are the bridge between the content in the model, and the
HTML given back to the browser.  Since ``repoze.bfg`` is very
type-centric, URLs grab information of a certain type.  Once we have
the information and its type, we can grab a view that is registered
for that type.

.. note::

  This "Step 01" doesn't use a template.  The "view" we define is done
  in Python, which generates the HTML.  Most applications will use
  templates to generate markup.

.. literalinclude:: step01/myapp/models.py
   :linenos:

#. Lines 3 provide the ``my_hello_view`` that was registered as the
   view.  ``configure.zcml``, on Line 10, said that the default URL
   for IMyModel content should run this ``my_hello_view`` function.

   The function is handed two pieces of information: the ``context``
   and the ``request``.  The ``context`` is the data at the current
   hop in the URL.  (That data comes from the model.)  The request is
   an instance of a WebOb request.

#. Lines 4-7 generate a WebOb Response object and return it.


Module ``run.py``
---------------------

We need a small Python module that sets everything, fires up a web
server, and handles incoming requests.  Later we'll see how to use a
Paste configuration file to do this work for us.

.. literalinclude:: step01/run.py
   :linenos:

#. Line 1 uses the web server from the Paste project.

#. Line 3 imports the big gun from ``repoze.bfg``.

#. Line 4 grabs the function that hands back the top of the
   application's model data.

#. Line 5 imports the package that we want to "publish".

#. Line 7 loads the big gun with the data and the package.

#. And finally, line 8 starts the web server on port 5432.


Running and Browsing the Application
---------------------------------------

We have our minimal application now in place.  We can run the
application as follows::

  cd docs/step01
  python run.py

.. note::

  Just to say it AGAIN: make sure the Python you are using is the
  Python from your virtual environment.  One way to ensure you always
  get the right scripts is to do ``source bin/activate`` from the top
  of your virtualenv.  This will modify your PATH to look first in the
  virtual env.

You should then see::

  $ python ./run.py 
  serving on 0.0.0.0:5432 view at http://127.0.0.1:5432

If you connect in a web browser to ``http://localhost:5432/a`` you
will see::

  Hello from a @ /a

This also works for ``http://localhost:5432/b``.  However, if you
connect to ``http://localhost:5432/c`` you will get::

  404 Not Found
  The resource could not be found.

  http://localhost:5432/c