This file is indexed.

/usr/share/pyshared/martian/scan.txt is in python-martian 0.14-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
Scanning modules
================

Martian can grok modules or packages. In order to grok packages, it
needs to scan all modules in it. The martian.scan package provides an
abstraction over packages and modules that helps with the scanning
process.

  >>> from martian.scan import module_info_from_dotted_name

We have provided a special test fixture package called stoneage that we are
going to scan, in ``martian.tests.stoneage``.

Modules
-------

The scanning module defines a class ``ModuleInfo`` that provides
information about a module or a package. Let's take a look at the
``cave`` module in the stone-age package::

  >>> module_info = module_info_from_dotted_name('martian.tests.stoneage.cave')

We get a ``ModuleInfo`` object representing the ``cave module::

  >>> module_info
  <ModuleInfo object for 'martian.tests.stoneage.cave'>

``cave`` is a module, not a package.

  >>> module_info.isPackage()
  False

We can retrieve the name of the module::

  >>> module_info.name
  'cave'

We can also retrieve the dotted name of the module::

  >>> module_info.dotted_name
  'martian.tests.stoneage.cave'

And the dotted name of the package the module is in::

  >>> module_info.package_dotted_name
  'martian.tests.stoneage'

It is possible to get the actual module object that the ModuleInfo
object stands for, in this case the package's ``cave.py``::

  >>> module = module_info.getModule()
  >>> module
  <module 'martian.tests.stoneage.cave' from '...cave.py...'>

We can store a module-level annotation in the module::

  >>> module.__grok_foobar__ = 'GROK LOVE FOO'

The ModuleInfo object allows us to retrieve the annotation again::

  >>> module_info.getAnnotation('grok.foobar', None)
  'GROK LOVE FOO'

If a requested annotation does not exist, we get the default value::

  >>> module_info.getAnnotation('grok.barfoo', 42)
  42

A module has no sub-modules in it (only packages have this)::

  >>> module_info.getSubModuleInfos()
  []

Trying to retrieve any sub modules will give back None::

  >>> print module_info.getSubModuleInfo('doesnotexist')
  None

Packages
--------

Now let's scan a package::

  >>> module_info = module_info_from_dotted_name('martian.tests.stoneage')

We will get a ModuleInfo instance representing the ``stoneage`` package::

  >>> module_info
  <ModuleInfo object for 'martian.tests.stoneage'>

The object knows it is a package::

  >>> module_info.isPackage()
  True

Like with the module, we can get the package's name::

  >>> module_info.name
  'stoneage'

We can also get the package's dotted name back from it::

  >>> module_info.dotted_name
  'martian.tests.stoneage'

It is also possible to get the dotted name of the nearest package the
package resides in. This will always be itself::

  >>> module_info.package_dotted_name
  'martian.tests.stoneage'

Now let's go into the package and a few sub modules that are in it::

  >>> module_info.getSubModuleInfo('cave')
  <ModuleInfo object for 'martian.tests.stoneage.cave'>

  >>> module_info.getSubModuleInfo('hunt')
  <ModuleInfo object for 'martian.tests.stoneage.hunt'>

Trying to retrieve non-existing sub modules gives back None::

  >>> print module_info.getSubModuleInfo('doesnotexist')
  None

It is possible to get the actual module object that the ModuleInfo
object stands for, in this case the package's ``__init__.py``::

  >>> module = module_info.getModule()
  >>> module
  <module 'martian.tests.stoneage' from '...__init__.py...'>

A package has sub modules::

  >>> sub_modules = module_info.getSubModuleInfos()
  >>> sub_modules
  [<ModuleInfo object for 'martian.tests.stoneage.cave'>,
   <ModuleInfo object for 'martian.tests.stoneage.hunt'>,
   <ModuleInfo object for 'martian.tests.stoneage.painting'>]

Resource paths
--------------

Resources can be stored in a directory alongside a module (in their
containing package).  We can get the path to such a resource directory
using the ``getResourcePath`` method.

For packages, a resource path will be a child of the package directory:

  >>> import os.path
  >>> expected_resource_path = os.path.join(os.path.dirname(
  ...     module.__file__), 'stoneage-templates')
  >>> resource_path = module_info.getResourcePath('stoneage-templates')
  >>> resource_path == expected_resource_path
  True

For modules, a resource path will be a sibling of the module's file:

  >>> cave_module_info = module_info_from_dotted_name(
  ...    'martian.tests.stoneage.cave')
  >>> expected_resource_path = os.path.join(os.path.dirname(
  ...     cave_module_info.getModule().__file__), 'cave-templates')
  >>> resource_path = cave_module_info.getResourcePath('cave-templates')
  >>> resource_path == expected_resource_path
  True


Skipping packages and modules
-----------------------------

By default no packages and modules are skipped from the grokking
procedure to guarantee a generic behaviour::

  >>> from martian.scan import ModuleInfo, module_info_from_dotted_name
  >>> module_info = module_info_from_dotted_name(
  ...     'martian.tests.withtestspackages')
  >>> module_info
  <ModuleInfo object for 'martian.tests.withtestspackages'>
  >>> # *Will* contain the module info for the tests and ftests packages
  >>> print module_info.getSubModuleInfos()
  [...<ModuleInfo object for 'martian.tests.withtestspackages.tests'>...]

You can, however, tell ``getSubmoduleInfos()`` to skip certain names
of packages and modules. To do that, you have to give a filter
function which takes a name and returns a boolean. Names, for which
the function returns ``True`` are skipped from the result.

For example, to get only those packages, which are *not* named 'tests'
nor 'ftests' we could do::

  >>> from martian.scan import ModuleInfo, module_info_from_dotted_name
  >>> no_tests_filter = lambda x: x in ['tests', 'ftests']
  >>> module_info = module_info_from_dotted_name(
  ...     'martian.tests.withtestsmodules', exclude_filter=no_tests_filter)
  >>> module_info
  <ModuleInfo object for 'martian.tests.withtestsmodules'>
  >>> no_tests_filter = lambda x: x in ['tests', 'ftests']
  >>> print module_info.getSubModuleInfos()
  [<ModuleInfo object for 'martian.tests.withtestsmodules.subpackage'>]

By default __main__ packages are always ignored::

  >>> module_info = module_info_from_dotted_name(
  ...     'martian.tests.with__main__')
  >>> print module_info.getSubModuleInfos()
  [<ModuleInfo object for 'martian.tests.with__main__.package'>]


Non-modules that look like modules
----------------------------------

Sometimes the environment (an editor or network file system, for
instance) will create a situation where there is a file or directory
that looks like a Python module or package but is in fact not really
one (file name starts with a dot, for instance). Module and package
names must be valid Python identifiers.

The package ``martian.tests.withbogusmodules`` contains only one real
module and one real package. The rest are almost right, but do not
start with an underscore and a letter and are therefore not valid. We
will see that Martian will ignore these other things::

  >>> module_info = module_info_from_dotted_name(
  ...     'martian.tests.withbogusmodules')
  >>> module_info.getSubModuleInfos()
  [<ModuleInfo object for 'martian.tests.withbogusmodules.nonbogus'>, 
   <ModuleInfo object for 'martian.tests.withbogusmodules.subpackage'>]

Packages which contain .pyc files only
--------------------------------------

When a .py file in a package is renamed, an "orphaned" .pyc object is
often left around.  By default, Martian will ignore such .pyc files:

  >>> import martian.tests.withpyconly
  >>> from martian.tests.withpyconly import foo
  >>> d = os.path.abspath(os.path.dirname(martian.tests.withpyconly.__file__))
  >>> os.rename(os.path.join(d, 'foo.py'), os.path.join(d, 'foo.py_aside'))
  >>> module_info = module_info_from_dotted_name(
  ...     'martian.tests.withpyconly')
  >>> module_info.getSubModuleInfos()
  [<ModuleInfo object for 'martian.tests.withpyconly.subpackage'>]

However, if ``ignore_nonsource=False`` is passed to
``module_info_from_dotted_name`` (or friends, such as
``module_info_from_module``), we will pick up these modules::

  >>> module_info = module_info_from_dotted_name(
  ...     'martian.tests.withpyconly', ignore_nonsource=False)
  >>> module_info.getSubModuleInfos()
  [<ModuleInfo object for 'martian.tests.withpyconly.foo'>,
   <ModuleInfo object for 'martian.tests.withpyconly.subpackage'>]
  >>> # rename back to normal name
  >>> os.rename(os.path.join(d, 'foo.py_aside'), os.path.join(d, 'foo.py'))