Ran update-copyright.py
[hooke.git] / doc / hacking.txt
1 *******
2 Hacking
3 *******
4
5 .. toctree::
6    :maxdepth: 2
7
8    testing
9
10 Dependencies
11 ============
12
13 To clean up the internals, were going to go crazy on the
14 object-oriented front, and try to keep the core functionality free of
15 any dependencies other than the `Python Standard Library`_, Numpy_,
16 Scipy_, and PyYAML_.
17
18 .. _Python Standard Library: http://docs.python.org/library/
19 .. _Numpy: http://numpy.scipy.org/
20 .. _Scipy: http://www.scipy.org/
21 .. _PyYAML: http://pyyaml.org/
22
23 To make a responsive user interface in parallel with data processing
24 and possible GUIs, we'll use Python's multiprocessing_ module.  This
25 module is new in Python 2.6, but 2.6 usage is becoming fairly
26 widespread.  Certainly more widespread than any alternative queue
27 module that I know of.  Since we're leveraging the power of the
28 standard library, we use configparser_ for the config files.
29
30 .. _multiprocessing: http://docs.python.org/dev/library/multiprocessing.html
31 .. _configparser: http://docs.python.org/library/configparser.html
32
33 On the testing side, the need to stick to the standard library relaxes
34 (developers can install extra packages), so we can use nose_.  See
35 the :doc:`testing` section for more information.
36
37 .. _nose: http://somethingaboutorange.com/mrl/projects/nose/0.11.3/
38
39
40 Principles
41 ==========
42
43 Hooke aims to be easily modified and extended by new recruits.  To
44 make this easier, we try to abide by several programming practices.
45
46 * `DRY`_ (Don't Repeat Yourself), also phrased as "Every piece of
47   knowledge must have a single, unambiguous, authoritative
48   representation within a system."
49 * `LoD`_ (Law of Demeter): Don't reach through layers, e.g. `a.b.c.d()`.
50
51 .. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
52 .. _LoD: http://en.wikipedia.org/wiki/Law_of_Demeter
53
54
55 Architecture
56 ============
57
58 Hooke's main entry point is :class:`~hooke.hooke.Hooke`.
59 :class:`~hooke.hooke.Hooke` reads in the configuration files and loads
60 Plugins_ and Drivers_.  Then it forks off a
61 :class:`~hooke.engine.CommandEngine` instance to execute Commands_,
62 and a :class:`~hooke.ui.UserInterface` instance to connect the
63 :class:`~hooke.engine.CommandEngine` with the user.  The
64 :class:`~hooke.engine.CommandEngine` runs in a subprocess, which
65 allows command execution to occur in parallel with
66 :class:`~hooke.ui.UserInterface` interaction.  The two processes
67 communicate via two :class:`multiprocessing.Queue`\s.
68
69 There are a number of special classes availiable to structure queue
70 communications.  See :mod:`~hooke.interaction` and
71 :class:`~hooke.command.CommandExit` for details.
72
73 Plugins
74 -------
75
76 :class:`~hooke.plugin.Plugin`\s contain bundles of Commands_,
77 representing the various operations a user can carry out through the
78 Hooke interface.
79
80 :class:`~hooke.plugin.Plugin`\s can depend on other
81 :class:`~hooke.plugin.Plugin`\s, so you shouldn't need to repeat code.
82 One central :class:`~hooke.plugin.Plugin` can provide useful
83 functionality to several dependent :class:`~hooke.plugin.Plugin`\s.
84
85 There is a :class:`~hooke.plugin.Plugin` subtype
86 :class:`~hooke.plugin.Builtin` which is just like a
87 :class:`~hooke.plugin.Plugin`, but is considered fundamental enough to
88 not be optional.  :class:`~hooke.plugin.Builtin`\s are always loaded.
89
90 Commands
91 ~~~~~~~~
92
93 :class:`~hooke.command.Command`\s specify user-actions in an
94 interface-agnostic manner.  This makes writing
95 :class:`~hooke.ui.UserInterface`\s easier, because you don't need to
96 know anything about particular :class:`~hooke.plugin.Plugin`\s or
97 :class:`~hooke.command.Command`\s, you just need to be able to explain
98 the base classes for you user and then speak the language of
99 :mod:`~hooke.interaction` and :class:`~hooke.command.CommandExit` with
100 the :class:`~hooke.engine.CommandEngine` process.
101
102 Drivers
103 -------
104
105 :class:`~hooke.driver.Driver`\s are responsible for reading assorted
106 data files into Hooke's Data_ structure.
107
108 Data
109 ----
110
111 Experiments
112 ~~~~~~~~~~~
113
114 Force spectroscopy experiments come in several major flavors.  Each
115 flavor gets its own subclass of :class:`~hooke.experiment.Experiment`
116 in :mod:`~hooke.experiment`.  For example, force clamp experiments are
117 :class:`~hooke.experiment.ForceClamp`.  This gives Drivers_ a way to
118 tag experimental data so Commands_ know what they are working with.
119
120 Curves
121 ~~~~~~
122
123 Experiments_ tags need a data-holding container to tag, and
124 :class:`~hooke.curve.Curve`\s are that container.  Each
125 :class:`~hooke.curve.Curve` can hole several blocks of
126 :class:`~hooke.curve.Data` (for example approach and retract curves in
127 a :class:`~hooke.experiment.VelocityClamp` experiment would be
128 seperate blocks).  :class:`~hooke.curve.Curve`\s also have an
129 :attr:`~hooke.curve.Curve.info` attribute for persistently storing
130 arbitrary data.
131
132 Playlists
133 ~~~~~~~~~
134
135 Normally you'll want to analyze multiple Curves_ in one session.
136 :class:`~hooke.playlist.Playlist`\s provide a convenient container for
137 Curves_, and the subclass :class:`~hooke.playlist.FilePlaylist` add
138 persistant file backing (save, load, etc.).
139
140 Utilities
141 ---------
142
143 There are a number of general coding features we need for Hooke that
144 are not provided by Python's standard library.  We factor those
145 features out into :mod:`~hooke.util`.
146
147 There are also a number of features who's standard library support
148 changes with different versions of Python.  :mod:`~hooke.compat`
149 provides a uniform interface to those tools so that Hooke will work
150 with several Python versions.
151
152 Analysis
153 --------
154
155 The :class:`hooke.curve.Data` blocks store data in various states of
156 processing.  For example, velocity clamp drivers will load two columns
157 of data: `z piezo (m)` and `deflection (m)` (all column names have the
158 `name (unit)` format, see :func:`~hooke.util.si.split_data_label`).
159 Most data processing consists of manipulating current block
160 information to create additional data columns in the same block.  For
161 example, :class:`~hooke.plugin.vclamp.SurfaceContactCommand` usually
162 uses the `z piezo (m)` and `deflection (m)` columns to add
163 `surface distance (m)` and `surface adjusted deflection (m)` columns.
164 However, you might want to use e.g. `median filtered deflection (m)`
165 instead of `deflection (m)`.  Because of this, analysis plugins should
166 use :class:`~hooke.command.Argument`\s rather than hard-coding source
167 or target column or info dict names.  See
168 :class:`~hooke.plugin.vclamp.SurfaceContactCommand` for an example of
169 the recommended approach.
170
171 Also keep in mind that some analyses will not generate columns that
172 are the same size as the source data
173 (e.g. :class:`~hooke.plugin.flatfilt.FlatPeaksCommand` and
174 :class:`~hooke.plugin.curve.PowerSpectrumCommand`).  These commands
175 will either stash information in the :class:`~hooke.curve.Data`'s
176 `.info` dictionary (e.g. a list of peaks) and/or add new
177 :class:`~hooke.curve.Data` blocks to the parent
178 :class:`~hooke.curve.Curve`.  The main reason for adding new blocks
179 rather than storing all the data in `.info` is to take advantage of
180 built in :class:`~hooke.curve.Data` processing
181 :class:`~hooke.command.Command`\s.  For example, the power spectrum
182 from :class:`~hooke.plugin.curve.PowerSpectrumCommand` can be easily
183 exported to a text file.  However, extra care must be taken to avoid
184 name collisions or ambiguity, since the output blocks must be unique
185 on a :class:`~hooke.curve.Curve`-wide level, while `Data.info` output
186 need only be unique on a :class:`~hooke.curve.Data`-wide level.
187
188 GUI
189 ---
190
191 :mod:`hooke.ui.gui` contains enough code that you might want a word
192 about its organization before diving into the code.  Information flows
193 like this:
194
195 .. image:: img/gui_flow/gui_flow.svg
196   
197 With the following naming scheme in HookeFrame:
198
199   ===================  ==================
200   callbacks            ``_on_*``
201   response processors  ``_postprocess_*``
202   ===================  ==================