0
# Rating System
1
2
Comprehensive quality assessment system with pluggable tests that evaluate various aspects of Python packaging best practices. The rating system provides detailed feedback, actionable recommendations, and numerical scores from 0-10 with humorous cheese-themed descriptions.
3
4
## Capabilities
5
6
### Core Rating Function
7
8
**rate(data, skip_tests=None)**
9
10
```python { .api }
11
def rate(data, skip_tests=None):
12
"""Rate package metadata quality using comprehensive test suite.
13
14
Args:
15
data: Package metadata dictionary from data extraction modules
16
skip_tests: List of test class names to skip during evaluation
17
18
Returns:
19
tuple: (rating: int, failures: list[str])
20
- rating: Numerical score from 0-10
21
- failures: List of failure messages for failed tests
22
23
Example:
24
>>> data = projectdata.get_data('/path/to/project')
25
>>> rating, failures = rate(data)
26
>>> print(f"Rating: {rating}/10")
27
>>> for failure in failures:
28
... print(f"- {failure}")
29
"""
30
```
31
32
The main rating function that:
33
34
- Runs all enabled tests against package metadata
35
- Calculates weighted score based on test importance
36
- Returns detailed failure messages for improvement guidance
37
- Supports fatal tests that force rating to 0
38
- Handles test skipping for specific use cases
39
40
### Test Discovery
41
42
**get_all_tests()**
43
44
```python { .api }
45
def get_all_tests():
46
"""Get list of all available test class names.
47
48
Returns:
49
list: List of test class names for use with skip_tests parameter
50
51
Example:
52
['Name', 'Version', 'VersionIsString', 'PEPVersion', 'Description',
53
'LongDescription', 'Classifiers', 'ClassifierVerification', ...]
54
"""
55
```
56
57
**get_code_licenses()**
58
59
```python { .api }
60
def get_code_licenses():
61
"""Build mapping of license short codes to classifier strings.
62
63
Returns:
64
dict: Mapping from license codes (e.g., 'MIT', 'GPL') to
65
sets of corresponding trove classifiers
66
67
Example:
68
{'MIT': {'License :: OSI Approved :: MIT License'},
69
'GPL': {'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', ...}}
70
"""
71
```
72
73
### Constants and Configuration
74
75
**ALL_TESTS**
76
77
```python { .api }
78
ALL_TESTS: list
79
"""List of all available test instances.
80
81
Contains instantiated test objects for all quality checks.
82
Used internally by the rating system to run evaluations.
83
"""
84
```
85
86
**LEVELS**
87
88
```python { .api }
89
LEVELS: list
90
"""Rating descriptions with cheese-themed messages.
91
92
Index corresponds to rating (0-10):
93
- 0: "This cheese seems to contain no dairy products"
94
- 1: "Vieux Bologne"
95
- 2: "Limburger"
96
- ...
97
- 10: "Your cheese is so fresh most people think it's a cream: Mascarpone"
98
"""
99
```
100
101
**CODE_LICENSES**
102
103
```python { .api }
104
CODE_LICENSES: dict
105
"""Mapping of license codes to trove classifier sets.
106
107
Built from trove-classifiers package, provides lookup from
108
common license abbreviations to their full classifier names.
109
"""
110
```
111
112
**PEP386_RE**
113
114
```python { .api }
115
PEP386_RE: re.Pattern
116
"""Compiled regex pattern for validating PEP-386 version format.
117
118
Used internally by PEPVersion test to validate legacy version formats.
119
Matches versions like '1.0', '1.0.1', '1.0a1', '1.0.post1', '1.0.dev1'.
120
"""
121
```
122
123
**PEP440_RE**
124
125
```python { .api }
126
PEP440_RE: re.Pattern
127
"""Compiled regex pattern for validating PEP-440 version format.
128
129
Used internally by PEPVersion test to validate modern version formats.
130
Supports epochs, pre-releases, post-releases, dev releases, and local versions.
131
"""
132
```
133
134
**SHORT_NAME_RE**
135
136
```python { .api }
137
SHORT_NAME_RE: re.Pattern
138
"""Compiled regex pattern for extracting license short names from classifiers.
139
140
Used by get_code_licenses() to parse license abbreviations from
141
trove classifier strings like 'License :: OSI Approved :: MIT License'.
142
"""
143
```
144
145
## Test Classes
146
147
The rating system includes comprehensive tests organized by category:
148
149
### Fatal Tests
150
151
Tests that must pass for any meaningful rating:
152
153
**Name**
154
- Verifies package has a name field
155
- Fatal: Package receives rating 0 if missing
156
157
**Version**
158
- Verifies package has a version field
159
- Fatal: Package receives rating 0 if missing
160
161
### Version Validation
162
163
**VersionIsString**
164
- Ensures version is a string type (weight: 50)
165
166
**PEPVersion**
167
- Validates version format against PEP-440 standard (weight: 50)
168
- Gives reduced weight for PEP-386 compliance only (weight: 10)
169
170
### Description and Documentation
171
172
**Description**
173
- Checks for package description > 10 characters (weight: 100)
174
- Fatal if no description exists
175
176
**LongDescription**
177
- Verifies long description > 100 characters (weight: 50)
178
179
**ValidREST**
180
- Validates ReStructuredText syntax in long description (weight: 50)
181
- Skips validation for markdown/plain text content types
182
183
### Metadata Completeness
184
185
**Classifiers**
186
- Requires presence of trove classifiers (weight: 100)
187
188
**ClassifierVerification**
189
- Validates classifiers against official trove classifier list (weight: 20)
190
- Allows private classifiers with "Private :: " prefix
191
192
**PythonClassifierVersion**
193
- Checks for specific Python version classifiers (weight: 25-100)
194
- Higher weight for detailed version specifications
195
196
**PythonRequiresVersion**
197
- Validates python_requires field with PEP-508 syntax (weight: 100)
198
199
**Keywords**
200
- Checks for keywords field (weight: 20)
201
202
### Contact Information
203
204
**Author**
205
- Requires author field or author name in author_email (weight: 100)
206
207
**AuthorEmail**
208
- Requires author_email field (weight: 100)
209
210
**Url**
211
- Requires project URL or project_urls field (weight: 20)
212
213
### Licensing
214
215
**Licensing**
216
- Validates license information consistency (weight: 50)
217
- Checks license field, license_expression, and license classifiers
218
- Prevents ambiguous license specifications
219
220
**DevStatusClassifier**
221
- Encourages development status classifier (weight: 20)
222
223
### Distribution and Maintenance
224
225
**SDist**
226
- Checks for source distribution on PyPI (weight: 100)
227
- Only applies to PyPI analysis mode
228
229
**BusFactor**
230
- Evaluates number of package owners on PyPI (weight: 50-100)
231
- Encourages multiple maintainers for reliability
232
233
### Build System Validation
234
235
**MissingBuildSystem**
236
- Warns about setup.cfg without build system definition (weight: 200)
237
238
**MissingPyProjectToml**
239
- Encourages pyproject.toml adoption (weight: 100)
240
241
**StoneAgeSetupPy**
242
- Warns about outdated setup.py usage (weight: 200)
243
244
### Optional Tests
245
246
**CheckManifest**
247
- Integrates check-manifest tool if available (weight: dynamic)
248
- Validates MANIFEST.in completeness and packaging consistency
249
- Weight starts at 0, becomes 200 when applicable to project
250
- Only runs if check-manifest package is installed and project has a path
251
- Detects missing files in source distributions
252
- Helps ensure all necessary files are included in published packages
253
254
## Usage Examples
255
256
```python
257
from pyroma.ratings import rate, get_all_tests, LEVELS
258
from pyroma.projectdata import get_data
259
260
# Basic rating
261
data = get_data('/path/to/project')
262
rating, failures = rate(data)
263
print(f"Rating: {rating}/10 - {LEVELS[rating]}")
264
265
# Skip specific tests
266
rating, failures = rate(data, skip_tests=['BusFactor', 'SDist'])
267
268
# List available tests
269
tests = get_all_tests()
270
print("Available tests:", ', '.join(tests))
271
272
# Detailed analysis
273
if failures:
274
print("Issues found:")
275
for failure in failures:
276
print(f" - {failure}")
277
else:
278
print("No issues found!")
279
```
280
281
## Test Base Classes
282
283
**BaseTest**
284
285
```python { .api }
286
class BaseTest:
287
"""Base class for all quality assessment tests.
288
289
Attributes:
290
fatal: bool - If True, failure results in rating 0
291
weight: int - Relative importance for scoring (default varies)
292
"""
293
294
fatal: bool = False
295
weight: int
296
297
def test(self, data): ...
298
def message(self): ...
299
```
300
301
**FieldTest**
302
303
```python { .api }
304
class FieldTest(BaseTest):
305
"""Base class for tests checking field presence and non-emptiness.
306
307
Attributes:
308
field: str - Metadata field name to check
309
"""
310
311
field: str
312
313
def test(self, data): ...
314
def message(self): ...
315
```