Fix existing Driver.is_me's crashes if path is a directory.
[hooke.git] / hooke / driver / __init__.py
1 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
2 #
3 # This file is part of Hooke.
4 #
5 # Hooke is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 #
10 # Hooke is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
13 # Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with Hooke.  If not, see
17 # <http://www.gnu.org/licenses/>.
18
19 """The driver module provides :class:`Driver`\s for identifying and
20 reading data files.
21
22 This allows Hooke to be data-file agnostic.  Drivers for various
23 commercial force spectroscopy microscopes are provided, and it's easy
24 to write your own to handle your lab's specific format.
25 """
26
27 import logging
28 import os.path
29
30 from ..config import Setting
31 from ..util.pluggable import IsSubclass, construct_graph
32
33
34 DRIVER_MODULES = [
35 #    ('csvdriver', True),
36 #    ('hdf5', True),
37     ('hemingway', True),
38     ('jpk', True),
39 #    ('mcs', True),
40 #    ('mfp1dexport', True),
41     ('mfp3d', True),
42     ('picoforce', True),
43     ('tutorial', True),
44     ('wtk', True),
45 ]
46 """List of driver modules and whether they should be included by
47 default.  TODO: autodiscovery
48 """
49
50 DRIVER_SETTING_SECTION = 'drivers'
51 """Name of the config section which controls driver selection.
52 """
53
54
55 class Driver (object):
56     """Base class for file format drivers.
57     
58     :attr:`name` identifies your driver and should match the module
59     name.
60     """
61     def __init__(self, name):
62         self.name = name
63         self.setting_section = '%s driver' % self.name
64
65     def dependencies(self):
66         """Return a list of :class:`Driver`\s we require."""
67         return []
68
69     def default_settings(self):
70         """Return a list of :class:`hooke.config.Setting`\s for any
71         configurable driver settings.
72
73         The suggested section setting is::
74
75             Setting(section=self.setting_section, help=self.__doc__)
76         """
77         return []
78
79     def is_me(self, path):
80         """Read the file and return True if the filetype can be
81         managed by the driver.  Otherwise return False.
82         """
83         return False
84
85     def read(self, path, info=None):
86         """Read data from `path` and return a
87         ([:class:`hooke.curve.Data`, ...], `info`) tuple.
88
89         The input `info` :class:`dict` may contain attributes read
90         from the :class:`~hooke.playlist.FilePlaylist`.
91
92         The `info` :class:`dict` must contain values for the keys:
93         'filetype' and 'experiment'.  See :class:`hooke.curve.Curve`
94         for details.
95         """
96         raise NotImplementedError
97
98     def logger(self):
99         return logging.getLogger('hooke')
100
101 # Construct driver dependency graph and load default drivers.
102
103 DRIVER_GRAPH = construct_graph(
104     this_modname=__name__,
105     submodnames=[name for name,include in DRIVER_MODULES],
106     class_selector=IsSubclass(Driver, blacklist=[Driver]))
107 """Topologically sorted list of all possible :class:`Driver`\s.
108 """
109
110 def default_settings():
111     settings = [Setting(DRIVER_SETTING_SECTION,
112                         help='Enable/disable default drivers.')]
113     for dnode in DRIVER_GRAPH:
114         driver = dnode.data
115         default_include = [di for mod_name,di in DRIVER_MODULES
116                            if mod_name == driver.name][0]
117         help = driver.__doc__.split('\n', 1)[0]
118         settings.append(Setting(
119                 section=DRIVER_SETTING_SECTION,
120                 option=driver.name,
121                 value=default_include,
122                 type='bool',
123                 help=help,
124                 ))
125     for dnode in DRIVER_GRAPH:
126         driver = dnode.data
127         settings.extend(driver.default_settings())
128     return settings