compatibility 2.1.0__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {compatibility-2.1.0 → compatibility-2.3.0}/PKG-INFO +16 -13
  2. {compatibility-2.1.0 → compatibility-2.3.0}/README.md +9 -7
  3. {compatibility-2.1.0 → compatibility-2.3.0}/compatibility/__init__.py +1 -1
  4. compatibility-2.3.0/compatibility/__main__.py +33 -0
  5. compatibility-2.1.0/compatibility/__main__.py → compatibility-2.3.0/compatibility/core.py +75 -19
  6. compatibility-2.3.0/compatibility/locales/compatibility.pot +179 -0
  7. compatibility-2.3.0/compatibility/locales/de/LC_MESSAGES/compatibility.mo +0 -0
  8. {compatibility-2.1.0 → compatibility-2.3.0}/compatibility/locales/de/LC_MESSAGES/compatibility.po +52 -32
  9. compatibility-2.3.0/compatibility/locales/es/LC_MESSAGES/compatibility.mo +0 -0
  10. {compatibility-2.1.0 → compatibility-2.3.0}/compatibility/locales/es/LC_MESSAGES/compatibility.po +52 -32
  11. compatibility-2.3.0/compatibility/locales/fr/LC_MESSAGES/compatibility.mo +0 -0
  12. {compatibility-2.1.0 → compatibility-2.3.0}/compatibility/locales/fr/LC_MESSAGES/compatibility.po +52 -32
  13. compatibility-2.3.0/compatibility/locales/nl/LC_MESSAGES/compatibility.mo +0 -0
  14. {compatibility-2.1.0 → compatibility-2.3.0}/compatibility/locales/nl/LC_MESSAGES/compatibility.po +52 -32
  15. {compatibility-2.1.0 → compatibility-2.3.0}/pyproject.toml +8 -7
  16. compatibility-2.1.0/compatibility/locales/de/LC_MESSAGES/compatibility.mo +0 -0
  17. compatibility-2.1.0/compatibility/locales/es/LC_MESSAGES/compatibility.mo +0 -0
  18. compatibility-2.1.0/compatibility/locales/fr/LC_MESSAGES/compatibility.mo +0 -0
  19. compatibility-2.1.0/compatibility/locales/nl/LC_MESSAGES/compatibility.mo +0 -0
  20. {compatibility-2.1.0 → compatibility-2.3.0}/LICENSE +0 -0
  21. {compatibility-2.1.0 → compatibility-2.3.0}/compatibility/err.py +0 -0
  22. {compatibility-2.1.0 → compatibility-2.3.0}/compatibility/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: compatibility
3
- Version: 2.1.0
3
+ Version: 2.3.0
4
4
  Summary: A library that checks whether the running version of Python is compatible and tested. Remind the user to check for updates of the library.
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Programming Language :: Python :: 3.15
17
18
  Classifier: Operating System :: OS Independent
18
19
  Classifier: Operating System :: POSIX :: Linux
19
20
  Classifier: Operating System :: Microsoft :: Windows
@@ -26,11 +27,11 @@ Classifier: Topic :: Software Development :: Quality Assurance
26
27
  Classifier: Topic :: Utilities
27
28
  Classifier: Typing :: Typed
28
29
  Provides-Extra: dev
29
- Requires-Dist: coverage[toml] (>=7.14,<8) ; extra == "dev"
30
- Requires-Dist: mypy (>=2.1,<3) ; extra == "dev"
31
- Requires-Dist: pytest (>=9.0,<10) ; extra == "dev"
32
- Requires-Dist: pytest-cov (>=7.1,<8) ; extra == "dev"
33
- Requires-Dist: ruff (>=0.15,<0.16) ; extra == "dev"
30
+ Requires-Dist: coverage[toml] (>=7.16.1,<8) ; extra == "dev"
31
+ Requires-Dist: mypy (>=2.3.1,<3) ; extra == "dev"
32
+ Requires-Dist: pytest (>=9.1.1,<10) ; extra == "dev"
33
+ Requires-Dist: pytest-cov (>=7.1.0,<8) ; extra == "dev"
34
+ Requires-Dist: ruff (>=0.16.8,<0.17) ; extra == "dev"
34
35
  Project-URL: Bug Tracker, https://github.com/RuedigerVoigt/compatibility/issues
35
36
  Project-URL: Changelog, https://github.com/RuedigerVoigt/compatibility/blob/main/CHANGELOG.md
36
37
  Project-URL: Documentation, https://github.com/RuedigerVoigt/compatibility
@@ -41,7 +42,7 @@ Description-Content-Type: text/markdown
41
42
  ![Supported Python Versions](https://img.shields.io/pypi/pyversions/compatibility)
42
43
  ![pypi version](https://img.shields.io/pypi/v/compatibility)
43
44
  ![Last commit](https://img.shields.io/github/last-commit/RuedigerVoigt/compatibility)
44
- [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://www.ruediger-voigt.eu/coverage/compatibility/index.html)
45
+ ![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)
45
46
  [![Downloads](https://pepy.tech/badge/compatibility/month)](https://pepy.tech/project/compatibility)
46
47
 
47
48
  # Python Compatibility Checker for Package Authors
@@ -96,7 +97,7 @@ All messages are available in English and German (plus AI-translated French, Dut
96
97
  - **Zero Dependencies**: Pure Python stdlib - no external packages required
97
98
  - **Type Safe**: Full type hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/)) for excellent IDE integration
98
99
  - **Well Tested**: 100% coverage (statements and branches), enforced in CI
99
- - **Python 3.10+**: Supports Python 3.10 through 3.14. Python 3.15 is already tested against its betas and will be officially supported once it is released.
100
+ - **Python 3.10+**: Supports Python 3.10 through 3.15.
100
101
 
101
102
  ## Installation
102
103
 
@@ -134,7 +135,7 @@ class MyPackage:
134
135
  python_version_support={
135
136
  'min_version': '3.10',
136
137
  'incompatible_versions': [],
137
- 'max_tested_version': '3.14'
138
+ 'max_tested_version': '3.15'
138
139
  }
139
140
  )
140
141
  ```
@@ -159,7 +160,7 @@ class MyAdvancedPackage:
159
160
  python_version_support={
160
161
  'min_version': '3.10',
161
162
  'incompatible_versions': ['3.9'],
162
- 'max_tested_version': '3.14'
163
+ 'max_tested_version': '3.15'
163
164
  },
164
165
  nag_over_update={
165
166
  'nag_days_after_release': 90, # Start reminding after 90 days
@@ -223,7 +224,7 @@ class Salted:
223
224
  python_version_support={
224
225
  'min_version': '3.10',
225
226
  'incompatible_versions': [],
226
- 'max_tested_version': '3.14'},
227
+ 'max_tested_version': '3.15'},
227
228
  nag_over_update={
228
229
  'nag_days_after_release': 30,
229
230
  'nag_in_hundred': 50},
@@ -232,7 +233,7 @@ class Salted:
232
233
  'full': {'Linux', 'MacOS', 'Windows'}
233
234
  })
234
235
  ```
235
- These settings ensure the package runs on Python 3.10 or higher, with testing confirmed through Python 3.14.
236
+ These settings ensure the package runs on Python 3.10 or higher, with testing confirmed through Python 3.15.
236
237
  Salted in that specific version is a relatively young package that will receive frequent updates. So beginning a month after the release this will nag the user over looking for an update every second time - provided the user activated logging.
237
238
 
238
239
  ## Parameters
@@ -341,7 +342,7 @@ DEBUG:compatibility:my_package fully supports Linux.
341
342
  INFO:compatibility:You are using my_package 1.0.0 (released: 2025-01-01)
342
343
  INFO:compatibility:Your version of my_package was released 120 days ago. Please check for updates.
343
344
  WARNING:compatibility:my_package has only partial support on Windows.
344
- WARNING:compatibility:You are running Python 3.15.final, but your version of my_package is only tested up to 3.14. Please check for updates.
345
+ WARNING:compatibility:You are running Python 3.16.final, but your version of my_package is only tested up to 3.15. Please check for updates.
345
346
  ERROR:compatibility:This version of my_package is incompatible with Windows!
346
347
  ```
347
348
 
@@ -370,6 +371,8 @@ Each available language has one of the following quality levels:
370
371
 
371
372
  The AI-translated languages are marked as such in the message catalog (`.po`) header until a native speaker has reviewed them. Corrections and reviews from native speakers are very welcome.
372
373
 
374
+ To add a new language, start from the template `compatibility/locales/compatibility.pot`, which lists every message.
375
+
373
376
  Set `language_messages='auto'` to follow the user's environment locale (`LANGUAGE`/`LC_ALL`/`LC_MESSAGES`/`LANG`); if no matching catalog is available, messages fall back to English.
374
377
 
375
378
  ## Exceptions
@@ -1,7 +1,7 @@
1
1
  ![Supported Python Versions](https://img.shields.io/pypi/pyversions/compatibility)
2
2
  ![pypi version](https://img.shields.io/pypi/v/compatibility)
3
3
  ![Last commit](https://img.shields.io/github/last-commit/RuedigerVoigt/compatibility)
4
- [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://www.ruediger-voigt.eu/coverage/compatibility/index.html)
4
+ ![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)
5
5
  [![Downloads](https://pepy.tech/badge/compatibility/month)](https://pepy.tech/project/compatibility)
6
6
 
7
7
  # Python Compatibility Checker for Package Authors
@@ -56,7 +56,7 @@ All messages are available in English and German (plus AI-translated French, Dut
56
56
  - **Zero Dependencies**: Pure Python stdlib - no external packages required
57
57
  - **Type Safe**: Full type hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/)) for excellent IDE integration
58
58
  - **Well Tested**: 100% coverage (statements and branches), enforced in CI
59
- - **Python 3.10+**: Supports Python 3.10 through 3.14. Python 3.15 is already tested against its betas and will be officially supported once it is released.
59
+ - **Python 3.10+**: Supports Python 3.10 through 3.15.
60
60
 
61
61
  ## Installation
62
62
 
@@ -94,7 +94,7 @@ class MyPackage:
94
94
  python_version_support={
95
95
  'min_version': '3.10',
96
96
  'incompatible_versions': [],
97
- 'max_tested_version': '3.14'
97
+ 'max_tested_version': '3.15'
98
98
  }
99
99
  )
100
100
  ```
@@ -119,7 +119,7 @@ class MyAdvancedPackage:
119
119
  python_version_support={
120
120
  'min_version': '3.10',
121
121
  'incompatible_versions': ['3.9'],
122
- 'max_tested_version': '3.14'
122
+ 'max_tested_version': '3.15'
123
123
  },
124
124
  nag_over_update={
125
125
  'nag_days_after_release': 90, # Start reminding after 90 days
@@ -183,7 +183,7 @@ class Salted:
183
183
  python_version_support={
184
184
  'min_version': '3.10',
185
185
  'incompatible_versions': [],
186
- 'max_tested_version': '3.14'},
186
+ 'max_tested_version': '3.15'},
187
187
  nag_over_update={
188
188
  'nag_days_after_release': 30,
189
189
  'nag_in_hundred': 50},
@@ -192,7 +192,7 @@ class Salted:
192
192
  'full': {'Linux', 'MacOS', 'Windows'}
193
193
  })
194
194
  ```
195
- These settings ensure the package runs on Python 3.10 or higher, with testing confirmed through Python 3.14.
195
+ These settings ensure the package runs on Python 3.10 or higher, with testing confirmed through Python 3.15.
196
196
  Salted in that specific version is a relatively young package that will receive frequent updates. So beginning a month after the release this will nag the user over looking for an update every second time - provided the user activated logging.
197
197
 
198
198
  ## Parameters
@@ -301,7 +301,7 @@ DEBUG:compatibility:my_package fully supports Linux.
301
301
  INFO:compatibility:You are using my_package 1.0.0 (released: 2025-01-01)
302
302
  INFO:compatibility:Your version of my_package was released 120 days ago. Please check for updates.
303
303
  WARNING:compatibility:my_package has only partial support on Windows.
304
- WARNING:compatibility:You are running Python 3.15.final, but your version of my_package is only tested up to 3.14. Please check for updates.
304
+ WARNING:compatibility:You are running Python 3.16.final, but your version of my_package is only tested up to 3.15. Please check for updates.
305
305
  ERROR:compatibility:This version of my_package is incompatible with Windows!
306
306
  ```
307
307
 
@@ -330,6 +330,8 @@ Each available language has one of the following quality levels:
330
330
 
331
331
  The AI-translated languages are marked as such in the message catalog (`.po`) header until a native speaker has reviewed them. Corrections and reviews from native speakers are very welcome.
332
332
 
333
+ To add a new language, start from the template `compatibility/locales/compatibility.pot`, which lists every message.
334
+
333
335
  Set `language_messages='auto'` to follow the user's environment locale (`LANGUAGE`/`LC_ALL`/`LC_MESSAGES`/`LANG`); if no matching catalog is available, messages fall back to English.
334
336
 
335
337
  ## Exceptions
@@ -5,7 +5,7 @@ tested. Remind the user to check for updates of the library.
5
5
 
6
6
  import importlib.metadata
7
7
 
8
- from compatibility.__main__ import (
8
+ from compatibility.core import (
9
9
  Check,
10
10
  NagOverUpdate,
11
11
  PythonVersionSupport,
@@ -0,0 +1,33 @@
1
+ """
2
+ Entry point for `python -m compatibility` and a deprecated import alias.
3
+
4
+ The library code lives in `compatibility.core`. This module used to hold it,
5
+ so its public names are re-exported here to keep old imports such as
6
+ `from compatibility.__main__ import Check` working. Importing this module
7
+ emits a DeprecationWarning; import from `compatibility` instead.
8
+
9
+ Copyright (c) 2021-2026 Rüdiger Voigt and contributors
10
+ Released under the Apache License 2.0
11
+ """
12
+
13
+ import warnings
14
+
15
+ from compatibility import NAME, __version__
16
+ from compatibility.core import ( # noqa: F401 (re-exported for old imports)
17
+ SUPPORTED_LANGUAGES,
18
+ Check,
19
+ NagOverUpdate,
20
+ PythonVersionSupport,
21
+ SystemSupport,
22
+ logger,
23
+ )
24
+
25
+ if __name__ == '__main__':
26
+ print(f'{NAME} {__version__}')
27
+ else:
28
+ warnings.warn(
29
+ 'Importing from compatibility.__main__ is deprecated and will be '
30
+ 'removed in version 3. Import from compatibility instead '
31
+ '(e.g. "from compatibility import Check").',
32
+ DeprecationWarning,
33
+ stacklevel=2)
@@ -20,7 +20,7 @@ import platform
20
20
  import random
21
21
  import re
22
22
  import sys
23
- from typing import Literal, Optional, TypedDict, Union
23
+ from typing import Literal, TypedDict
24
24
 
25
25
  from compatibility import err
26
26
 
@@ -54,7 +54,7 @@ class SystemSupport(TypedDict, total=False):
54
54
  incompatible: set[str]
55
55
 
56
56
 
57
- class Check():
57
+ class Check:
58
58
  """Main Class of the compatibility package: check Python version
59
59
  and time since release."""
60
60
 
@@ -63,14 +63,21 @@ class Check():
63
63
  VERSION_REGEX = re.compile(
64
64
  r"(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<releaselevel>\b(alpha|beta|candidate|final)\b))?")
65
65
 
66
+ # Plausibility bounds for release_date. A date well into the future is
67
+ # almost always a typo (e.g. a wrong year); a very old date suggests
68
+ # release_date was never updated. Both only warn -- a near-future date is
69
+ # legitimate while developing toward a planned release.
70
+ FUTURE_LIMIT_DAYS = 60
71
+ PAST_LIMIT_YEARS = 8
72
+
66
73
  def __init__(self,
67
74
  package_name: str,
68
75
  package_version: str,
69
- release_date: Union[datetime.date, str],
70
- python_version_support: Optional[PythonVersionSupport] = None,
71
- nag_over_update: Optional[NagOverUpdate] = None,
76
+ release_date: datetime.date | str,
77
+ python_version_support: PythonVersionSupport | None = None,
78
+ nag_over_update: NagOverUpdate | None = None,
72
79
  language_messages: str = 'en',
73
- system_support: Optional[SystemSupport] = None,
80
+ system_support: SystemSupport | None = None,
74
81
  on_incompatible: Literal['raise', 'warn', 'ignore'] = 'raise'):
75
82
  """Initialize compatibility checker and perform all validation checks.
76
83
 
@@ -103,6 +110,8 @@ class Check():
103
110
  (log a warning and continue), or 'ignore' (continue silently).
104
111
 
105
112
  Raises:
113
+ TypeError: If package_name, package_version, or
114
+ language_messages is not a string.
106
115
  ValueError: If package_name or package_version is empty, if
107
116
  language_messages or on_incompatible is invalid, or if
108
117
  parameters are malformed.
@@ -113,6 +122,17 @@ class Check():
113
122
  contradictory entries, or if min_version is higher than
114
123
  max_tested_version.
115
124
  """
125
+ # Guard clause: .strip() below only works on strings, so reject other
126
+ # types with a clear error instead of a raw AttributeError. This runs
127
+ # before the translation is set up (which depends on
128
+ # language_messages), so the message is not localized.
129
+ for name, value in (('package_name', package_name),
130
+ ('package_version', package_version),
131
+ ('language_messages', language_messages)):
132
+ if not isinstance(value, str):
133
+ raise TypeError(
134
+ f'Parameter {name} must be a string, '
135
+ f'not {type(value).__name__}.')
116
136
  self.package_name = package_name.strip()
117
137
  self.package_version = package_version.strip()
118
138
  self.language_messages = language_messages.strip()
@@ -134,6 +154,7 @@ class Check():
134
154
  self._ = self._translation.gettext
135
155
  self.release_date = self.__coerce_date(release_date)
136
156
  self.check_params()
157
+ self.__warn_implausible_release_date()
137
158
  self.check_python_version(python_version_support)
138
159
  self.check_system(system_support)
139
160
  self.log_version_info()
@@ -141,7 +162,7 @@ class Check():
141
162
  self.check_version_age(nag_over_update)
142
163
 
143
164
  def __coerce_date(
144
- self, date_to_coerce: Union[str, datetime.date]) -> datetime.date:
165
+ self, date_to_coerce: str | datetime.date) -> datetime.date:
145
166
  """Convert a string to datetime.date and validate.
146
167
 
147
168
  Accepts either a datetime.date object (returned as-is) or a string
@@ -172,6 +193,25 @@ class Check():
172
193
  raise err.BadDateType(
173
194
  self._('date_to_coerce must be either string or datetime.date'))
174
195
 
196
+ def __warn_implausible_release_date(self) -> None:
197
+ """Warn (never raise) if release_date is implausibly far off.
198
+
199
+ A date more than ``FUTURE_LIMIT_DAYS`` ahead is almost always a typo
200
+ (e.g. a wrong year), and a date more than ``PAST_LIMIT_YEARS`` old
201
+ suggests release_date was not updated. Neither is fatal: a near-future
202
+ date is legitimate while developing toward a planned release, so both
203
+ cases only log a warning and leave the date usable.
204
+ """
205
+ days_from_today = (self.release_date - datetime.date.today()).days
206
+ if days_from_today > self.FUTURE_LIMIT_DAYS:
207
+ logger.warning(
208
+ self._("The release_date %s is more than %s days in the future. Please check it is correct."),
209
+ self.release_date, self.FUTURE_LIMIT_DAYS)
210
+ elif days_from_today < -(self.PAST_LIMIT_YEARS * 365):
211
+ logger.warning(
212
+ self._("The release_date %s is more than %s years in the past. Please check it is correct."),
213
+ self.release_date, self.PAST_LIMIT_YEARS)
214
+
175
215
  def check_params(self) -> None:
176
216
  """Validate that required parameters are non-empty and valid.
177
217
 
@@ -199,7 +239,7 @@ class Check():
199
239
  raise ValueError(self._('Invalid value for on_incompatible!'))
200
240
 
201
241
  def check_python_version(self,
202
- python_version_support: Optional[PythonVersionSupport] = None
242
+ python_version_support: PythonVersionSupport | None = None
203
243
  ) -> None:
204
244
  """Validate that the running Python version is supported.
205
245
 
@@ -213,8 +253,8 @@ class Check():
213
253
  no version checking is performed.
214
254
 
215
255
  Raises:
216
- ValueError: If python_version_support dict is malformed or
217
- contains invalid version strings.
256
+ ValueError: If python_version_support is not a dict, is malformed,
257
+ or contains invalid version strings.
218
258
  err.ParameterContradiction: If 'min_version' is higher than
219
259
  'max_tested_version'.
220
260
  RuntimeError: If running Python version is below minimum or is
@@ -224,6 +264,9 @@ class Check():
224
264
  if not python_version_support:
225
265
  # Setting python_version_support is not required
226
266
  return None
267
+ if not isinstance(python_version_support, dict):
268
+ raise ValueError(
269
+ self._('Parameter python_version_support must be a dictionary'))
227
270
 
228
271
  min_version, max_version = self.__validate_python_version_support(
229
272
  python_version_support)
@@ -256,7 +299,8 @@ class Check():
256
299
  re-parse (and assert-guard) the strings in the comparison helpers.
257
300
 
258
301
  Raises:
259
- ValueError: If the dict has the wrong keys, or any of the version
302
+ ValueError: If the dict has the wrong keys, if
303
+ 'incompatible_versions' is not a list, or any of the version
260
304
  strings ('min_version', 'max_tested_version', or any entry of
261
305
  'incompatible_versions') cannot be parsed.
262
306
  err.ParameterContradiction: If 'min_version' is higher than
@@ -287,6 +331,12 @@ class Check():
287
331
  python_version_support['max_tested_version'])
288
332
  if not max_match:
289
333
  raise ValueError(self._('Value for key max_tested_version incorrect.'))
334
+ # A bare string here would otherwise be iterated character by character
335
+ # (yielding a misleading "cannot be parsed" error), and an empty string
336
+ # would pass silently. Require an actual list.
337
+ if not isinstance(python_version_support['incompatible_versions'], list):
338
+ raise ValueError(
339
+ self._('Value for key incompatible_versions must be a list.'))
290
340
  for version_string in python_version_support['incompatible_versions']:
291
341
  if not re.fullmatch(self.VERSION_REGEX, version_string):
292
342
  raise ValueError(
@@ -368,7 +418,7 @@ class Check():
368
418
  )
369
419
 
370
420
  def check_system(self,
371
- system_support: Optional[SystemSupport]) -> None:
421
+ system_support: SystemSupport | None) -> None:
372
422
  """Validate operating system compatibility.
373
423
 
374
424
  Checks whether the current OS (Linux, MacOS, or Windows) is fully
@@ -527,10 +577,13 @@ class Check():
527
577
  (int 0-100, percentage chance of showing nag message).
528
578
 
529
579
  Raises:
530
- ValueError: If a key is missing, if a value is not an int, if
531
- nag_days_after_release is negative, or if nag_in_hundred is
532
- not between 0 and 100.
580
+ ValueError: If nag_over_update is not a dict, a key is missing, a
581
+ value is not an int, nag_days_after_release is negative, or
582
+ nag_in_hundred is not between 0 and 100.
533
583
  """
584
+ if not isinstance(nag_over_update, dict):
585
+ raise ValueError(
586
+ self._('Parameter nag_over_update must be a dictionary'))
534
587
  nag_days_after_release, nag_in_hundred = self.__validate_nag_over_update(
535
588
  nag_over_update)
536
589
  if nag_in_hundred == 0:
@@ -557,8 +610,8 @@ class Check():
557
610
  A tuple of (nag_days_after_release, nag_in_hundred).
558
611
 
559
612
  Raises:
560
- ValueError: If a key is missing, if a value is not an int (floats
561
- and strings are rejected rather than coerced), if
613
+ ValueError: If a key is missing, if a value is not an int (bool,
614
+ floats, and strings are rejected rather than coerced), if
562
615
  nag_days_after_release is negative, or if nag_in_hundred is
563
616
  not between 0 and 100.
564
617
  """
@@ -568,8 +621,11 @@ class Check():
568
621
  nag_days_after_release = nag_over_update['nag_days_after_release']
569
622
  nag_in_hundred = nag_over_update['nag_in_hundred']
570
623
  # Reject non-int values explicitly: int() would silently truncate a
571
- # float (3.7 -> 3) or accept a numeric string.
572
- if (not isinstance(nag_days_after_release, int)
624
+ # float (3.7 -> 3) or accept a numeric string. bool is checked first
625
+ # because it is a subclass of int (True would otherwise pass as 1).
626
+ if (isinstance(nag_days_after_release, bool)
627
+ or isinstance(nag_in_hundred, bool)
628
+ or not isinstance(nag_days_after_release, int)
573
629
  or not isinstance(nag_in_hundred, int)):
574
630
  raise ValueError(self._('Some key in nag_over_update has wrong type!'))
575
631
  if nag_days_after_release < 0:
@@ -0,0 +1,179 @@
1
+ # Translation template for the compatibility package.
2
+ # Copyright (c) 2021-2026 Rüdiger Voigt and contributors
3
+ # This file is distributed under the same license as the compatibility package.
4
+ # Generated by `python compile_translations.py --extract`. Do not edit by hand.
5
+ #
6
+ #, fuzzy
7
+ msgid ""
8
+ msgstr ""
9
+ "Project-Id-Version: compatibility\n"
10
+ "Report-Msgid-Bugs-To: \n"
11
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "Language: \n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+
19
+ #: compatibility/core.py:191
20
+ msgid "Non-existing or incomplete date!"
21
+ msgstr ""
22
+
23
+ #: compatibility/core.py:194
24
+ msgid "date_to_coerce must be either string or datetime.date"
25
+ msgstr ""
26
+
27
+ #: compatibility/core.py:208
28
+ #, python-format
29
+ msgid "The release_date %s is more than %s days in the future. Please check it is correct."
30
+ msgstr ""
31
+
32
+ #: compatibility/core.py:212
33
+ #, python-format
34
+ msgid "The release_date %s is more than %s years in the past. Please check it is correct."
35
+ msgstr ""
36
+
37
+ #: compatibility/core.py:229
38
+ msgid "Missing package name!"
39
+ msgstr ""
40
+
41
+ #: compatibility/core.py:231
42
+ msgid "Missing package version!"
43
+ msgstr ""
44
+
45
+ #: compatibility/core.py:236
46
+ msgid "Invalid value for language_messages!"
47
+ msgstr ""
48
+
49
+ #: compatibility/core.py:239
50
+ msgid "Invalid value for on_incompatible!"
51
+ msgstr ""
52
+
53
+ #: compatibility/core.py:269
54
+ msgid "Parameter python_version_support must be a dictionary"
55
+ msgstr ""
56
+
57
+ #: compatibility/core.py:311
58
+ msgid "Parameter python_version_support incomplete!"
59
+ msgstr ""
60
+
61
+ #: compatibility/core.py:314
62
+ msgid "Parameter python_version_support: too many keys!"
63
+ msgstr ""
64
+
65
+ #: compatibility/core.py:322
66
+ msgid "Parameter python_version_support contains unknown keys."
67
+ msgstr ""
68
+
69
+ #: compatibility/core.py:329
70
+ msgid "Value for key min_version is incorrect."
71
+ msgstr ""
72
+
73
+ #: compatibility/core.py:333
74
+ msgid "Value for key max_tested_version incorrect."
75
+ msgstr ""
76
+
77
+ #: compatibility/core.py:339
78
+ msgid "Value for key incompatible_versions must be a list."
79
+ msgstr ""
80
+
81
+ #: compatibility/core.py:343
82
+ msgid "Some string in incompatible_versions cannot be parsed."
83
+ msgstr ""
84
+
85
+ #: compatibility/core.py:351
86
+ #, python-format
87
+ msgid "min_version (%(min)s) is higher than max_tested_version (%(max)s)."
88
+ msgstr ""
89
+
90
+ #: compatibility/core.py:382
91
+ #, python-format
92
+ msgid "You use %(running)s, but need at least %(required)s to run %(package)s."
93
+ msgstr ""
94
+
95
+ #: compatibility/core.py:391
96
+ #, python-format
97
+ msgid "Your version of Python is not compatible with this version of %(package)s. Please check for updates."
98
+ msgstr ""
99
+
100
+ #: compatibility/core.py:414
101
+ #, python-format
102
+ msgid "You are running Python %s, but your version of %s is only tested up to %s. Please check for updates."
103
+ msgstr ""
104
+
105
+ #: compatibility/core.py:444
106
+ msgid "Parameter system_support must be a dictionary"
107
+ msgstr ""
108
+
109
+ #: compatibility/core.py:471
110
+ msgid "Unknown key in dictionary system_support"
111
+ msgstr ""
112
+
113
+ #: compatibility/core.py:473
114
+ #, python-format
115
+ msgid "Use a set to hold values for %s."
116
+ msgstr ""
117
+
118
+ #: compatibility/core.py:477
119
+ #, python-format
120
+ msgid "Invalid system in %s. Allowed: %s"
121
+ msgstr ""
122
+
123
+ #: compatibility/core.py:494
124
+ msgid "Contradiction: System cannot simultaneously be fully AND only partially supported."
125
+ msgstr ""
126
+
127
+ #: compatibility/core.py:500
128
+ msgid "Contradiction: System cannot have full support AND be incompatible!"
129
+ msgstr ""
130
+
131
+ #: compatibility/core.py:516
132
+ #, python-format
133
+ msgid "%s fully supports %s."
134
+ msgstr ""
135
+
136
+ #: compatibility/core.py:520
137
+ #, python-format
138
+ msgid "%s has only partial support on %s."
139
+ msgstr ""
140
+
141
+ #: compatibility/core.py:525
142
+ #, python-format
143
+ msgid "This version of %s is incompatible with %s!"
144
+ msgstr ""
145
+
146
+ #: compatibility/core.py:530
147
+ #, python-format
148
+ msgid "%s's support for %s is unknown!"
149
+ msgstr ""
150
+
151
+ #: compatibility/core.py:561
152
+ #, python-format
153
+ msgid "You are using %(package)s %(version)s (released: %(date)s)"
154
+ msgstr ""
155
+
156
+ #: compatibility/core.py:586
157
+ msgid "Parameter nag_over_update must be a dictionary"
158
+ msgstr ""
159
+
160
+ #: compatibility/core.py:597
161
+ #, python-format
162
+ msgid "Your version of %s was released %s days ago. Please check for updates."
163
+ msgstr ""
164
+
165
+ #: compatibility/core.py:620
166
+ msgid "A key in nag_over_update is missing."
167
+ msgstr ""
168
+
169
+ #: compatibility/core.py:630
170
+ msgid "Some key in nag_over_update has wrong type!"
171
+ msgstr ""
172
+
173
+ #: compatibility/core.py:632
174
+ msgid "nag_days_after_release must not be negative."
175
+ msgstr ""
176
+
177
+ #: compatibility/core.py:634
178
+ msgid "nag_in_hundred must be int between 0 and 100."
179
+ msgstr ""