|
| 1 | +[](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=27&branchName=master) |
| 2 | +[](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=27&branchName=master) |
| 3 | + |
| 4 | +flake8-2020 |
| 5 | +=========== |
| 6 | + |
| 7 | +flake8 plugin which checks for misuse of `sys.version` or `sys.version_info` |
| 8 | + |
| 9 | +this will become a problem when `python3.10` or `python4.0` exists (presumably |
| 10 | +during the year 2020). |
| 11 | + |
| 12 | +you might also find an early build of [python3.10] useful |
| 13 | + |
| 14 | +[python3.10]: https://github.com/asottile/python3.10 |
| 15 | + |
| 16 | +## installation |
| 17 | + |
| 18 | +`pip install flake8-2020` |
| 19 | + |
| 20 | +## flake8 codes |
| 21 | + |
| 22 | +| Code | Description | |
| 23 | +|--------|--------------------------------------------------------| |
| 24 | +| YTT101 | `sys.version[:3]` referenced (python3.10) | |
| 25 | +| YTT102 | `sys.version[2]` referenced (python3.10) | |
| 26 | +| YTT103 | `sys.version` compared to string (python3.10) | |
| 27 | +| YTT201 | `sys.version_info[0] == 3` referenced (python4) | |
| 28 | +| YTT202 | `six.PY3` referenced (python4) | |
| 29 | +| YTT203 | `sys.version_info[1]` compared to integer (python4) | |
| 30 | +| YTT204 | `sys.version_info.minor` compared to integer (python4) | |
| 31 | +| YTT301 | `sys.version[0]` referenced (python10) | |
| 32 | +| YTT302 | `sys.version` compared to string (python10) | |
| 33 | +| YTT303 | `sys.version[:1]` referenced (python10) | |
| 34 | + |
| 35 | +## rationale |
| 36 | + |
| 37 | +lots of code incorrectly references the `sys.version` and `sys.version_info` |
| 38 | +members. in particular, this will cause some issues when the version of python |
| 39 | +after python3.9 is released. my current recommendation is 3.10 since I believe |
| 40 | +it breaks less code, here's a few patterns that will cause issues: |
| 41 | + |
| 42 | +```python |
| 43 | +# in python3.10 this will report as '3.1' (should be '3.10') |
| 44 | +python_version = sys.version[:3] # YTT101 |
| 45 | +# in python3.10 this will report as '1' (should be '10') |
| 46 | +py_minor = sys.version[2] |
| 47 | +# in python3.10 this will be False (which goes against developer intention) |
| 48 | +sys.version >= '3.5' # YTT103 |
| 49 | + |
| 50 | + |
| 51 | +# correct way to do this |
| 52 | +python_version = '{}.{}'.format(*sys.version_info) |
| 53 | +py_minor = str(sys.version_info[1]) |
| 54 | +sys.version_info >= (3, 5) |
| 55 | +``` |
| 56 | + |
| 57 | +```python |
| 58 | +# in python4 this will report as `False` (and suddenly run python2 code!) |
| 59 | +is_py3 = sys.version_info[0] == 3 # YTT201 |
| 60 | + |
| 61 | +# in python4 this will report as `False` (six violates YTT201!) |
| 62 | +if six.PY3: # YTT202 |
| 63 | + print('python3!') |
| 64 | + |
| 65 | +if sys.version_info[0] >= 3 and sys.version_info[1] >= 5: # YTT203 |
| 66 | + print('py35+') |
| 67 | + |
| 68 | +if sys.version_info.major >= 3 and sys.version_info.minor >= 6: # YTT204 |
| 69 | + print('py36+') |
| 70 | + |
| 71 | +# correct way to do this |
| 72 | +is_py3 = sys.version_info >= (3,) |
| 73 | + |
| 74 | +if not six.PY2: |
| 75 | + print('python3!') |
| 76 | + |
| 77 | +if sys.version_info >= (3, 5): |
| 78 | + print('py35+') |
| 79 | + |
| 80 | +if sys.version_info >= (3, 6): |
| 81 | + print('py36+') |
| 82 | +``` |
| 83 | + |
| 84 | +```python |
| 85 | +# in python10 this will report as '1' |
| 86 | +python_major_version = sys.version[0] # YTT301 |
| 87 | +# in python10 this will be False |
| 88 | +if sys.version >= '3': # YTT302 |
| 89 | + print('python3!') |
| 90 | +# in python10 this will be False |
| 91 | +if sys.version[:1] >= '3': # YTT303 |
| 92 | + print('python3!') |
| 93 | + |
| 94 | + |
| 95 | +# correct way to do this |
| 96 | +python_major_version = str(sys.version_info[0]) |
| 97 | + |
| 98 | +if sys.version_info >= (3,): |
| 99 | + print('python3!') |
| 100 | + |
| 101 | +if sys.version_info >= (3,): |
| 102 | + print('python3!') |
| 103 | +``` |
| 104 | + |
| 105 | +## as a pre-commit hook |
| 106 | + |
| 107 | +See [pre-commit](https://github.com/pre-commit/pre-commit) for instructions |
| 108 | + |
| 109 | +Sample `.pre-commit-config.yaml`: |
| 110 | + |
| 111 | +```yaml |
| 112 | +- repo: https://gitlab.com/pycqa/flake8 |
| 113 | + rev: 3.7.8 |
| 114 | + hooks: |
| 115 | + - id: flake8 |
| 116 | + additional_dependencies: [flake8-2020==1.6.0] |
| 117 | +``` |
0 commit comments