PageRenderTime 15ms CodeModel.GetById 1ms app.highlight 9ms RepoModel.GetById 2ms app.codeStats 0ms

/docs/source/tutorial/index.rst

https://bitbucket.org/prologic/circuits/
ReStructuredText | 346 lines | 230 code | 116 blank | 0 comment | 0 complexity | 57d7e087cde904093f018273860b87b7 MD5 | raw file
  1.. _Python Programming Language: http://www.python.org/
  2
  3
  4Tutorial
  5========
  6
  7
  8Overview
  9--------
 10
 11Welcome to the circuits tutorial. This 5-minute tutorial is going to walk you
 12through the basic concepts of circuits. The goal will be to introduce
 13new concepts incrementally with walk-through examples that you can try out!
 14By the time you've finished, you should have a good basic understanding
 15of circuits, how it feels and where to go from there.
 16
 17
 18The Component
 19-------------
 20
 21First up, let's show how you can use the ``Component`` and run it in a very
 22simple application.
 23
 24.. literalinclude:: 001.py
 25   :language: python
 26   :linenos:
 27
 28:download:`Download 001.py <001.py>`
 29
 30Okay so that's pretty boring as it doesn't do very much! But that's okay...
 31Read on!
 32
 33Let's try to create our own custom Component called ``MyComponent``.
 34
 35.. literalinclude:: 002.py
 36   :language: python
 37   :linenos:
 38
 39:download:`Download 002.py <002.py>`
 40
 41Okay, so this still isn't very sueful! But at least we can create
 42components with the behavior we want.
 43
 44Let's move on to something more interesting...
 45
 46
 47Event Handlers
 48--------------
 49
 50Let's now extend our little example to say "Hello World!" when its started.
 51
 52.. literalinclude:: 003.py
 53   :language: python
 54   :linenos:
 55
 56:download:`Download 003.py <003.py>`
 57
 58Here we've created a simple **Event Handler** that listens for events on
 59the "started" channel. Methods defined in a Component are converted into
 60Event Handlers.
 61
 62Running this we get::
 63   
 64   Hello World!
 65
 66
 67Alright! We have something slightly more useful! Whoohoo it says hello!
 68
 69.. note:: Press ^C (*Ctrl + C*) to exit.
 70
 71
 72Registering Components
 73----------------------
 74
 75So now that we've learned how to use a Component, create a custom Component
 76and create simple Event Handlers, let's try something a bit more complex
 77and create two components that each do something fairly simple.
 78
 79Let's create two components:
 80
 81- ``Bob``
 82- ``Fred``
 83
 84.. literalinclude:: 004.py
 85   :language: python
 86   :linenos:
 87
 88:download:`Download 004.py <004.py>`
 89
 90Notice the way we register the two components ``Bob`` and ``Fred`` together
 91? Don't worry if this doesn't make sense right now. Think of it as putting
 92two components together and plugging them into a circuits board.
 93
 94Running this example produces the following result::
 95   
 96   Hello I'm Bob!
 97   Hello I'm Fred!
 98
 99Cool! We have two components that each do something and print a simple
100message on the screen!
101
102
103Complex Components
104------------------
105
106Now, what if we wanted to create a Complex Component ? Let's say we wanted
107to create a new Component made up of two other smaller components ?
108
109We can do this by simply registering components to a Complex Component
110during initialization.
111
112.. literalinclude:: 005.py
113   :language: python
114   :linenos:
115
116:download:`Download 005.py <005.py>`
117
118So now ``Pound`` is a Component that consists of two other components
119registered to it: ``Bob`` and ``Fred``
120
121The output of this is identical to the previous::
122   
123   * <Pound/* 3391:MainThread (queued=0, channels=1, handlers=3) [R]>
124    * <Bob/* 3391:MainThread (queued=0, channels=1, handlers=1) [S]>
125    * <Fred/* 3391:MainThread (queued=0, channels=1, handlers=1) [S]>
126   Hello I'm Bob!
127   Hello I'm Fred!
128   
129The only difference is that ``Bob`` and ``Fred`` are now part of a more
130Complex Component called ``Pound``. This can be illustrated by the
131following diagram:
132
133.. graphviz::
134   
135   digraph G {
136      "Pound-1344" -> "Bob-9b0c";
137      "Pound-1344" -> "Fred-e98a";
138   }
139   
140.. note::
141   The extra lines in the above output are an ASCII representation of the
142   above graph (*produced by pydot + graphviz*).
143
144Cool :-)
145
146
147Component Inheritence
148---------------------
149
150Since circuits is a framework written for the `Python Programming
151Language`_ it naturally inherits properties of Object Orientated
152Programming (OOP) -- such as inheritence.
153
154So let's take our ``Bob`` and ``Fred`` components and create a Base
155Component called ``Dog`` and modify our two dogs (``Bob`` and ``Fred``) to
156subclass this.
157
158.. literalinclude:: 006.py
159   :language: python
160   :linenos:
161
162:download:`Download 006.py <006.py>`
163
164Now let's try to run this and see what happens::
165   
166  Woof! I'm Bob!
167  Woof! I'm Fred!
168
169So both dogs barked~ Hmmm
170
171
172Component Channels
173------------------
174
175What if we only want one of our dogs to bark ? How do we do this without
176causing the other one to bark as well ?
177
178Easy! Use a separate ``channel`` like so:
179
180.. literalinclude:: 007.py
181   :language: python
182   :linenos:
183
184:download:`Download 007.py <007.py>`
185
186.. note::
187   Events can be fired with either the ``.fire(...)`` or ``.fireEvent(...)``
188   method.
189
190If you run this, you'll get::
191   
192   Woof! I'm Bob!
193
194
195Event Objects
196-------------
197
198So far in our tutorial we have been defining an Event Handler for a builtin
199Event called ``Started`` (*which incidently gets fired on a channel called
200"started"*). What if we wanted to define our own Event Handlers and our own
201Events ? You've already seen how easy it is to create a new Event Handler
202by simply defining a normal Python method on a Component.
203
204Defining your own Events helps with documentation and testing and makes
205things a little easier.
206
207Example::
208   
209   class MyEvent(Event):
210      """MyEvent"""
211
212So here's our example where we'll define a new Event claled ``Bark``
213and make our ``Dog`` fire a ``Bark`` event when our application starts up.
214
215.. literalinclude:: 008.py
216   :language: python
217   :linenos:
218
219:download:`Download 008.py <008.py>`
220
221If you run this, you'll get::
222   
223   Woof! I'm Bob!
224   Woof! I'm Fred!
225
226
227The Debugger
228------------
229
230Lastly...
231
232Asynchronous programming has many advntages but can be a little harder to
233write and follow. A silently caught exception in an Event Handler, or an Event
234that never gets fired, or any number of other weird things can cause your
235application to fail and leave you scratching your head.
236
237Fortunately circuits comes with a ``Debugger`` Component to help you keep
238track of what's going on in your application, and allows you to tell what
239your application is doing.
240
241Let's say that we defined out ``bark`` Event Handler in our ``Dog``
242Component as follows::
243   
244   def bark(self):
245      print("Woof! I'm %s!" % name)
246
247Now clearly there is no such variable as ``name`` in the local scope.
248
249For reference here's the entire example...
250
251.. literalinclude:: 009.py
252   :language: python
253   :linenos:
254
255:download:`Download 009.py <009.py>`
256
257If you run this, you'll get:
258
259That's right! You get nothing! Why ? Well in circuits any error or
260exception that occurs in a running application is automatically caught and
261dealt with in a way that lets your application "keep on going". Crashing is
262unwanted behavior in a system so we expect to be able to recover from
263horrible situations.
264
265SO what do we do ? Welll that's easy. circuits come with a ``Debugger``
266that lets you log all events as well as all errors so you can quickly and
267easily discover which Event is causing a problem and which Event Handler to
268look at.
269
270If you change Line 34 of our example...
271
272From:
273
274.. literalinclude:: 009.py
275   :language: python
276   :lines: 34
277
278.. code-block:: python
279   
280   from circuits import Debugger
281
282   (Pound() + Debugger()).run()
283
284Then run this, you'll get the following::
285   
286   <Registered[bob:registered] [<Bob/bob 3191:MainThread (queued=0, channels=2, handlers=2) [S]>, <Pound/* 3191:MainThread (queued=0, channels=5, handlers=5) [R]>] {}>
287   <Registered[fred:registered] [<Fred/fred 3191:MainThread (queued=0, channels=2, handlers=2) [S]>, <Pound/* 3191:MainThread (queued=0, channels=5, handlers=5) [R]>] {}>
288   <Registered[*:registered] [<Debugger/* 3191:MainThread (queued=0, channels=1, handlers=1) [S]>, <Pound/* 3191:MainThread (queued=0, channels=5, handlers=5) [R]>] {}>
289   <Started[*:started] [<Pound/* 3191:MainThread (queued=0, channels=5, handlers=5) [R]>, None] {}>
290   <Bark[bob:bark] [] {}>
291   <Bark[fred:bark] [] {}>
292   <Error[*:exception] [<type 'exceptions.NameError'>, NameError("global name 'name' is not defined",), ['  File "/home/prologic/work/circuits/circuits/core/manager.py", line 459, in __handleEvent\n    retval = handler(*eargs, **ekwargs)\n', '  File "source/tutorial/009.py", line 22, in bark\n    print("Woof! I\'m %s!" % name)\n'], <bound method ?.bark of <Bob/bob 3191:MainThread (queued=0, channels=2, handlers=2) [S]>>] {}>
293   ERROR <listener on ('bark',) {target='bob', priority=0.0}> (<type 'exceptions.NameError'>): global name 'name' is not defined
294     File "/home/prologic/work/circuits/circuits/core/manager.py", line 459, in __handleEvent
295    retval = handler(*eargs, **ekwargs)
296     File "source/tutorial/009.py", line 22, in bark
297       print("Woof! I'm %s!" % name)
298   
299   <Error[*:exception] [<type 'exceptions.NameError'>, NameError("global name 'name' is not defined",), ['  File "/home/prologic/work/circuits/circuits/core/manager.py", line 459, in __handleEvent\n    retval = handler(*eargs, **ekwargs)\n', '  File "source/tutorial/009.py", line 22, in bark\n    print("Woof! I\'m %s!" % name)\n'], <bound method ?.bark of <Fred/fred 3191:MainThread (queued=0, channels=2, handlers=2) [S]>>] {}>
300   ERROR <listener on ('bark',) {target='fred', priority=0.0}> (<type 'exceptions.NameError'>): global name 'name' is not defined
301     File "/home/prologic/work/circuits/circuits/core/manager.py", line 459, in __handleEvent
302       retval = handler(*eargs, **ekwargs)
303     File "source/tutorial/009.py", line 22, in bark
304       print("Woof! I'm %s!" % name)
305   
306   ^C<Signal[*:signal] [2, <frame object at 0x808e8ec>] {}>
307   <Stopped[*:stopped] [<Pound/* 3191:MainThread (queued=0, channels=5, handlers=5) [S]>] {}>
308   <Stopped[*:stopped] [<Pound/* 3191:MainThread (queued=0, channels=5, handlers=5) [S]>] {}>
309   
310You'll notice whereas there was no output before there is now a pretty
311detailed output with the ``Debugger`` added to the application. Looking
312through the output, we find that the application does indeed start
313correctly, but when we fire our ``Bark`` Event it coughs up two exceptions,
314one for each of our dogs (``Bob`` and ``Fred``).
315
316From the error we can tell where the error is and roughly where to look in
317the code.
318
319.. note::
320   You'll notice many other events that are displayed in the above output.
321   These are all default events that circuits has builtin which your
322   application can respond to. Each builtin Event has a special meaning
323   with relation to the state of the application at that point.
324   
325   See: :py:mod:`circuits.core.events` for detailed documentation regarding
326   these events.
327
328The correct code for the ``bark`` Event Handler should be::
329   
330   def bark(self):
331       print("Woof! I'm %s!" % self.name)
332
333Running again with our coorection results in the expected output::
334   
335   Woof! I'm Bob!
336   Woof! I'm Fred!
337
338That's it folks!
339
340Hopefully this gives you a feel of what circuits is all about and a easy
341tutorial on some of the basic concepts. As you're no doubt itching to get
342started on your next circuits project, here's some recommended reading:
343
344- :doc:`../faq`
345- :doc:`../guides/index`
346- :doc:`../api/index`