You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Compatibility is a simple tool designed to be used by package authors. It does five things:
8
-
* Check whether the running Python interpreter version is supported, i.e. equal or higher than the minimum version and not in a list of incompatible versions. Raises a `RuntimeError` exception if the interpreter version is marked as incompatible.
9
-
* Log a warning if the running interpreter version is higher than the highest version used in tests.
10
-
* Log an info message with package name, version, and release date.
11
-
* Log an info message asking the user to check for updates if a defined number of days has passed since release. (For privacy reasons it is not checked whether a new version is actually available.)
12
-
* Check whether the operating system group (i.e. Linux, MacOS, or Windows) is fully supported, partially supported or marked as incompatible. Partial support logs an info message, while incompatibility yields an exception.
7
+
# Python Compatibility Checker for Package Authors
13
8
14
-
The prepared messages are available in English and German.
9
+
**Version guard your Python package • Check OS compatibility • Prevent runtime errors**
15
10
16
-
For these tasks it does not need any dependencies outside the Python standard library. The code has type hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/)).
11
+
Ensure your Python package runs on the right versions, warn users about untested versions, and gracefully handle incompatible environments.
17
12
18
-
# Installation
13
+
Compatibility is a lightweight, zero-dependency library that helps Python package authors and library developers provide a better user experience by checking Python version compatibility, operating system compatibility (Linux, macOS, Windows), and gently reminding users to update. Uses Python's standard `gettext` for translations and follows PEP 561 (typed package). Perfect for PyPI package maintainers who want to prevent cryptic errors and provide helpful guidance to users.
14
+
15
+
## Why Use This Library?
16
+
17
+
✅ **Prevent cryptic runtime errors** - Catch incompatible Python versions before they cause problems
18
+
✅ **Zero dependencies** - Uses only Python's standard library
19
+
✅ **Fully typed** - Complete type hints (PEP 484) for better IDE support
20
+
✅ **Multilingual** - Built-in English and German messages
21
+
✅ **User-friendly warnings** - Inform users about untested Python versions
22
+
✅ **OS compatibility checks** - Validate Linux, macOS, and Windows support
23
+
✅ **Update reminders** - Gently encourage users to check for package updates
24
+
✅ **High test coverage** - 99%+ coverage for reliability
25
+
26
+
## Table of Contents
27
+
28
+
-[What It Does](#what-it-does)
29
+
-[Key Features](#key-features)
30
+
-[Installation](#installation)
31
+
-[Quick Start](#quick-start)
32
+
-[Detailed Usage](#detailed-usage)
33
+
-[⚠️ Important: Where to Call Compatibility](#️-important-where-to-call-compatibility)
34
+
-[Complete Example](#complete-example)
35
+
-[Parameters](#parameters)
36
+
-[Required Parameters](#required-parameters)
37
+
-[Optional Parameters](#optional-parameters)
38
+
-[Version Strings](#version-strings)
39
+
-[Avoid Running Your Package with an Incompatible Version of Python](#avoid-running-your-package-with-an-incompatible-version-of-python)
40
+
-[Logging](#logging)
41
+
-[Exceptions](#exceptions)
42
+
-[Use Cases](#use-cases)
43
+
44
+
## What It Does
45
+
46
+
1.**Python Version Validation** - Check if the running Python interpreter meets minimum requirements and isn't in your list of incompatible versions. Raises `RuntimeError` for incompatible versions.
47
+
2.**Untested Version Warnings** - Warn users when running your package on Python versions newer than you've tested.
48
+
3.**Package Version Logging** - Log package name, version, and release date for better debugging.
49
+
4.**Privacy-Friendly Update Reminders** - Optionally remind users to check for updates after N days (without phoning home or checking if updates exist).
50
+
5.**Operating System Compatibility** - Validate whether the OS (Linux, macOS, Windows) is fully supported, partially supported, or incompatible.
51
+
52
+
All messages are available in English and German, selectable per-instance.
53
+
54
+
## Key Features
55
+
56
+
-**Zero Dependencies**: Pure Python stdlib - no external packages required
57
+
-**Type Safe**: Full type hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/)) for excellent IDE integration
58
+
-**Well Tested**: 97% minimum coverage enforced; typically 98-99%
59
+
-**Python 3.10+**: Supports Python 3.10 through 3.14
60
+
61
+
## Installation
19
62
20
63
```bash
21
64
pip install compatibility
22
65
```
23
66
24
-
# Usage
67
+
That's it! No other dependencies to manage.
68
+
69
+
## Quick Start
70
+
71
+
**Note:** To see compatibility's informational messages and warnings, configure logging first:
72
+
73
+
```python
74
+
import logging
75
+
logging.basicConfig(level=logging.INFO)
76
+
```
77
+
78
+
Here's a minimal example to get started:
79
+
80
+
```python
81
+
from datetime import date
82
+
import logging
83
+
import compatibility
84
+
85
+
# Configure logging to see messages
86
+
logging.basicConfig(level=logging.INFO)
87
+
88
+
classMyPackage:
89
+
def__init__(self):
90
+
compatibility.Check(
91
+
package_name='my_package',
92
+
package_version='1.0.0',
93
+
release_date=date(2025, 1, 1),
94
+
python_version_support={
95
+
'min_version': '3.10',
96
+
'incompatible_versions': [],
97
+
'max_tested_version': '3.14'
98
+
}
99
+
)
100
+
```
101
+
102
+
### Extended Example
103
+
104
+
Here's a more complete example using all optional features:
105
+
106
+
```python
107
+
from datetime import date
108
+
import logging
109
+
import compatibility
110
+
111
+
logging.basicConfig(level=logging.INFO)
112
+
113
+
classMyAdvancedPackage:
114
+
def__init__(self):
115
+
compatibility.Check(
116
+
package_name='my_advanced_package',
117
+
package_version='2.0.0',
118
+
release_date=date(2025, 1, 15),
119
+
python_version_support={
120
+
'min_version': '3.10',
121
+
'incompatible_versions': ['3.9'],
122
+
'max_tested_version': '3.14'
123
+
},
124
+
nag_over_update={
125
+
'nag_days_after_release': 90, # Start reminding after 90 days
126
+
'nag_in_hundred': 25# Show reminder 25% of the time
127
+
},
128
+
language_messages='en', # or 'de' for German
129
+
system_support={
130
+
'full': {'Linux', 'MacOS'}, # Fully tested
131
+
'partial': {'Windows'}, # Should work, less tested
132
+
'incompatible': set() # No known incompatibilities
133
+
}
134
+
)
135
+
```
136
+
137
+
## Detailed Usage
138
+
139
+
### ⚠️ Important: Where to Call Compatibility
140
+
141
+
**Call `compatibility.Check()` in your class constructor, NOT in `__init__.py`**
142
+
143
+
```python
144
+
# ❌ DON'T DO THIS (in __init__.py)
145
+
import compatibility
146
+
compatibility.Check(...) # Runs at import time, before user configures logging
147
+
148
+
# ✅ DO THIS (in your class __init__)
149
+
classMyClass:
150
+
def__init__(self):
151
+
compatibility.Check(...) # Runs when instantiated, after logging is configured
152
+
```
153
+
154
+
**Why?** If you call it in `__init__.py`, it runs immediately on import before users can configure their logging levels. This means users might see unwanted DEBUG messages. Calling it in the class constructor lets users set up logging first.
25
155
26
-
It is important that you **do NOT call `compatibility` in the `__init__.py` file of your package, but in the constructor (`def __init__()`) of your class instead.** If you start the check in the `__init__.py` file, then it will run once you *import* the package. This goes well *if* the user already set the level for `logging`. If that is not the case, the user will see all messages including those on the `DEBUG` level. This is not a problem if the check is done in the constructor.
156
+
### Complete Example
27
157
28
-
As an example the relevant parts of the constructor of the [salted](https://github.com/RuedigerVoigt/salted) package:
158
+
Here's a real-world example from the [salted](https://github.com/RuedigerVoigt/salted) package:
29
159
30
160
```python
31
161
# [...]
@@ -67,10 +197,15 @@ Salted in that specific version is a relatively young package that will receive
67
197
68
198
## Parameters
69
199
70
-
*`package_name` (required): the name of your package.
71
-
*`package_version` (required): the version number of your package as a string.
72
-
*`release_date` (required): requires a `datetime` object (like `date(2021,1,1)`), or a string in the exact format `YYYY-MM-DD`.
73
-
*`python_version_support` (optional): requires a dictionary with the three following keys:
200
+
### Required Parameters
201
+
202
+
*`package_name`: the name of your package.
203
+
*`package_version`: the version number of your package as a string.
204
+
*`release_date`: requires a `datetime` object (like `date(2021,1,1)`), or a string in the exact format `YYYY-MM-DD`.
205
+
206
+
### Optional Parameters
207
+
208
+
*`python_version_support`: requires a dictionary with the three following keys:
74
209
*`min_version`: a string with the number of the oldest supported version (like `'3.10'`).
75
210
*`incompatible_versions`: a list of incompatible versions that will raise the `RuntimeError` exception if they try to run your package.
76
211
*`max_tested_version`: the latest version of the interpreter you successfully tested your code with.
@@ -83,6 +218,15 @@ Salted in that specific version is a relatively young package that will receive
83
218
*`partial`: The set of systems that should work, but are not as rigorously tested as those with full support. A system found running here logs a warning.
84
219
*`incompatible`: The set of systems of which you know they will fail to run the code properly. If an OS in this set tries to run the code, this will yield a `RuntimeError` exception.
|`full`| DEBUG | No | Production-tested, fully supported |
226
+
|`partial`| WARNING | No | Should work, but less rigorously tested |
227
+
|`incompatible`| ERROR | Yes (`RuntimeError`) | Known to fail |
228
+
| Not listed | INFO | No | Support status unknown |
229
+
86
230
## Version strings
87
231
88
232
For compatibility checks three elements of the version string are recognized:
@@ -149,3 +293,23 @@ The `compatibility` package may raise the following exceptions:
149
293
*`ValueError`: Raised when invalid parameters are provided to the `Check` class.
150
294
*`compatibility.err.BadDate`: Raised when the `release_date` parameter contains an invalid or malformed date.
151
295
*`compatibility.err.ParameterContradiction`: Raised when conflicting parameters are provided (e.g., a system marked as both fully supported and incompatible).
296
+
297
+
## Use Cases
298
+
299
+
### When Your Package Requires Specific Python Versions
300
+
Use `min_version` to prevent your package from running on older Python versions that lack required features (like match statements, structural pattern matching, or newer typing features).
301
+
302
+
### When You Know Specific Python Versions Are Broken
303
+
Use `incompatible_versions` to block specific Python versions where your package has known issues (e.g., bugs in Python itself, or dependencies that break on certain versions).
304
+
305
+
### When Users Report Bugs on Untested Python Versions
306
+
Use `max_tested_version` to warn users when they're running your package on newer Python versions you haven't tested yet. This helps manage expectations and reduces false bug reports.
307
+
308
+
### When You Drop Support for Old Python Versions
309
+
After dropping Python 3.9 support, use this library to give users a clear error message instead of cryptic import errors or runtime failures.
310
+
311
+
### When Your Package Only Works on Certain Operating Systems
312
+
Use `system_support` to declare which operating systems (Linux, macOS, Windows) are fully supported, partially supported, or incompatible. For example, if your package uses Linux-specific system calls.
313
+
314
+
### When You Want Users to Update Old Package Versions
315
+
Use `nag_over_update` to gently remind users to check for updates after your package has been out for a while, without any privacy concerns (no network calls, no tracking).
0 commit comments