This file is indexed.

/usr/lib/python3/dist-packages/pyroma/ratings.py is in python3-pyroma 2.0.0b2-1.

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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# -*- coding: UTF-8 -*-
# This is a collection of "tests" done on the package data. The resut of the
# tests is used to give the package a rating.
#
# Each test has a couple of attributes. Both attributes are checked only after
# the test is performed so the test can choose to set the attributes dependning
# on the severity of the failure.
#
#     fatal:    If set to True, the failure of this test will cause the
#               package to achieve the rating of 1, which is minimum
#     weight:   The relative importance of the test.
#               If the test has fatal set to True this is ignored.
#
# Tests have two methods:
#     test(data): Performs the test on the given data. Returns True for pass
#                 False for fail and None for not applicable (meaning it will
#                 not be counted).

import re
from docutils.core import publish_parts
from docutils.utils import SystemMessage

try:
    stringtypes = basestring,
except NameError:
    stringtypes = str,

LEVELS = ["This cheese seems to contain no dairy products",
          "Vieux Bologne",
          "Limburger",
          "Gorgonzola",
          "Stilton",
          "Brie",
          "Comté",
          "Jarlsberg",
          "Philadelphia",
          "Cottage Cheese",
          "Your cheese is so fresh most people think it's a cream: Mascarpone"]


class BaseTest(object):
    fatal = False


class FieldTest(BaseTest):
    """Tests that a specific field is in the data and is not empty or False"""

    def test(self, data):
        return bool(data.get(self.field))

    def message(self):
        return ("Your package does not have %s data" % self.field) + (
            self.fatal and '!' or '.')


class Name(FieldTest):
    fatal = True
    field = 'name'


class Version(FieldTest):
    fatal = True
    field = 'version'


class VersionIsString(BaseTest):
    weight = 50

    def test(self, data):
        # Check that the version is a string
        version = data.get('version')
        return isinstance(version, stringtypes)

    def message(self):
        return 'The version number should be a string.'

VERSION_RE = re.compile(r'''
    ^
    (?P<version>\d+\.\d+)          # minimum 'N.N'
    (?P<extraversion>(?:\.\d+)*)   # any number of extra '.N' segments
    (?:
        (?P<prerel>[abc]|rc)       # 'a'=alpha, 'b'=beta, 'c'=release candidate
                                   # 'rc'= alias for release candidate
        (?P<prerelversion>\d+(?:\.\d+)*)
    )?
    (?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)?
    $''', re.VERBOSE)


class PEP386Version(BaseTest):
    weight = 50

    def test(self, data):
        # Check that the version number complies to PEP-386:
        version = data.get('version')
        match = VERSION_RE.search(str(version))
        return match is not None

    def message(self):
        return "The package's version number does not comply with PEP-386."


class Description(BaseTest):
    weight = 100

    def test(self, data):
        description = data.get('description')
        if not description:
            # No description at all. That's fatal.
            self.fatal = True
            return False
        self.fatal = False
        return len(description) > 10

    def message(self):
        if self.fatal:
            return 'The package had no description!'
        else:
            return ("The package's description should be longer than "
                    "10 characters.")


class LongDescription(BaseTest):
    weight = 50

    def test(self, data):
        long_description = data.get('long_description', '')
        if not isinstance(long_description, stringtypes):
            long_description = ''
        return len(long_description) > 100

    def message(self):
        return "The package's long_description is quite short."


class Classifiers(FieldTest):
    weight = 100
    field = 'classifiers'


class PythonVersion(BaseTest):

    def test(self, data):
        self._major_version_specified = False

        classifiers = data.get('classifiers', [])
        for classifier in classifiers:
            parts = [p.strip() for p in classifier.split('::')]
            if parts[0] == 'Programming Language' and parts[1] == 'Python':
                if len(parts) == 2:
                    # Specified Python, but no version.
                    continue
                version = parts[2]
                try:
                    float(version)
                except ValueError:
                    # Not a proper Python version
                    continue
                try:
                    int(version)
                except ValueError:
                    # It's a valid float, but not a valid int. Hence it's
                    # something like "2.7" or "3.3" but not just "2" or "3".
                    # This is a good specification, and we only need one.
                    # Set weight to 100 and finish.
                    self.weight = 100
                    return True

                # It's a valid int, meaning it specified "2" or "3".
                self._major_version_specified = True

        # There was some sort of failure:
        if self._major_version_specified:
            # Python 2 or 3 was specified but no more detail than that:
            self.weight = 25
        else:
            # No Python version specified at all:
            self.weight = 100
        return False

    def message(self):
        if self._major_version_specified:
            return "The classifiers should specify what minor versions of "\
                   "Python you support as well as what major version."
        return "You should specify what Python versions you support."


class Keywords(FieldTest):
    weight = 20
    field = 'keywords'


class Author(FieldTest):
    weight = 100
    field = 'author'


class AuthorEmail(FieldTest):
    weight = 100
    field = 'author_email'


class Url(FieldTest):
    weight = 20
    field = 'url'


class License(FieldTest):
    weight = 50
    field = 'license'


class ZipSafe(BaseTest):

    def test(self, data):
        if data.get('_setuptools'):
            self.weight = 20
            return 'zip_safe' in data
        else:
            self.weight = 0
            return True

    def message(self):
        return "You are using Setuptools or Distribute but do not specify if "\
               "this package is zip_safe or not. You should specify it, as "\
               "it defaults to True, which you probably do not want."


class TestSuite(BaseTest):

    def test(self, data):
        if data.get('_setuptools'):
            self.weight = 50
            if 'test_suite' in data:
                return True
            if 'cmdclass' in data:
                if 'test' in data.get('cmdclass', []):
                    return True
            return False
        else:
            self.weight = 0
            return True

    def message(self):
        return "Setuptools and Distribute support running tests. By "\
               "specifying a test suite, it's easy to find and run tests "\
               "both for automated tools and humans."


class SDist(BaseTest):
    weight = 100

    def test(self, data):
        if '_has_sdist' not in data:
            # We aren't checking on PyPI
            self.weight = 0
            return None
        return data['_has_sdist']

    def message(self):
        return ("You have no source distribution on the Cheeseshop. "
                "Uploading the source distribution to the Cheeseshop ensures "
                "maximum availability of your package.")


class PackageDocs(BaseTest):
    weight = 0  # Just a recommendation

    def test(self, data):
        return data.get('_packages_docs') or data.get('_readthe_docs')

    def message(self):
        return "You might want to host your documentation on pythonhosted.org"\
               " or readthedocs.org."


class ValidREST(BaseTest):

    weight = 50

    def test(self, data):
        source = data.get('long_description', '')
        try:
            # Try to publish to HTML and see if we get an error or not.
            publish_parts(source=source, writer_name='html4css1')
        except SystemMessage as e:
            self._message = e.args[0].strip()
            return False

        return True

    def message(self):
        return 'Your long_description is not valid ReST: ' + self._message


class BusFactor(BaseTest):

    def test(self, data):
        if '_owners' not in data:
            self.weight = 0
            return None

        if len(data.get('_owners', [])) == 1:
            self.weight = 100
            return False

        if len(data.get('_owners', [])) == 2:
            self.weight = 50
            return False

        # Three or more, that's good.
        self.weight = 100
        return True

    def message(self):
        return "You should have three or more owners of the project on PyPI."


ALL_TESTS = [
    Name(),
    Version(),
    VersionIsString(),
    PEP386Version(),
    Description(),
    LongDescription(),
    Classifiers(),
    PythonVersion(),
    Keywords(),
    Author(),
    AuthorEmail(),
    Url(),
    License(),
    ZipSafe(),
    TestSuite(),
    SDist(),
    PackageDocs(),
    ValidREST(),
    BusFactor(),
]


def rate(data):
    if not data:
        # No data was gathered. Fail:
        return (0, ["I couldn't find any package data"])
    fails = []
    good = 0
    bad = 0
    fatality = False
    for test in ALL_TESTS:
        res = test.test(data)
        if res is False:
            fails.append(test.message())
            if test.fatal:
                fatality = True
            else:
                bad += test.weight
        elif res is True:
            if not test.fatal:
                good += test.weight
    # If res is None, it's ignored.
    if fatality:
        # A fatal tests failed. That means we give a 0 rating:
        return 0, fails
    # Multiply good by 9, and add 1 to get a rating between
    # 1: All non-fatal tests failed.
    # 10: All tests succeeded.
    return (good*9)//(good+bad)+1, fails