Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump minimum Python version to 3.8 #325

Merged
merged 11 commits into from
Nov 18, 2023
33 changes: 1 addition & 32 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,10 @@ jobs:
- macos-latest
- windows-latest
python:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'

# Python 3.6 is not available on Ubuntu 22.04, which is what
# ubuntu-latest points to as of Q4 2022¹, so replace that job with 3.6
# on Ubuntu 20.04.
# -trs, 22 Nov 2022
#
# ¹ <https://github.blog/changelog/2022-11-09-github-actions-ubuntu-latest-workflows-will-use-ubuntu-22-04/>
#
# A bodged https://github.com/actions/python-version build of 3.7.17
# for macOS mistakenly doesn't include the bz2 module of the stdlib¹,
# which breaks us because some of our deps (fsspec, at the least)
# assume bz2 is available² (though that will be fixed in its next
# release³). Replace the 3.7 macOS job with a 3.7.16 job.
# -trs, 22 June 2023
#
# ¹ <https://github.com/actions/setup-python/issues/682>
# ² <https://github.com/nextstrain/cli/pull/289#issuecomment-1595417903>
# ³ <https://github.com/fsspec/filesystem_spec/pull/1295>
exclude:
- os: ubuntu-latest
python: '3.6'
- os: macos-latest
python: '3.7'
include:
- os: ubuntu-20.04
python: '3.6'
- os: macos-latest
python: '3.7.16'
runs-on: ${{ matrix.os }}
defaults:
run:
Expand Down Expand Up @@ -240,11 +211,9 @@ jobs:
- macos-latest
- windows-latest
python:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
# XXX TODO: Add 3.10 here once supported by Conda/Bioconda/Conda Forge.
- '3.10'
runs-on: ${{ matrix.os }}
defaults:
run:
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ development source code and as such may not be routinely kept up to date.

# __NEXT__

This release drops support for Python versions 3.6 and 3.7.
([#325](https://github.com/nextstrain/cli/pull/325))

## Improvements

* `nextstrain remote upload` now skips gzip compression when uploading
Expand Down
2 changes: 1 addition & 1 deletion doc/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Development of `nextstrain-cli` happens at <https://github.com/nextstrain/cli>.

We currently target compatibility with Python 3.6 and higher.
We currently target compatibility with Python 3.8 and higher.

Versions for this project follow the [Semantic Versioning rules][].

Expand Down
2 changes: 1 addition & 1 deletion doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ From PyPI
---------

.. note::
Nextstrain CLI is written in Python 3 and requires at least Python 3.6. There
Nextstrain CLI is written in Python 3 and requires at least Python 3.8. There
are many ways to install Python 3 on Windows, macOS, or Linux, including the
`official packages`_, `Homebrew`_ for macOS, and the `Anaconda Distribution`_.
Details are beyond the scope of this guide, but make sure you install Python
Expand Down
7 changes: 2 additions & 5 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[mypy]
# We currently aim for compat with 3.6.
python_version = 3.6
# We currently aim for compat with 3.8.
python_version = 3.8
namespace_packages = True

# Check function bodies which don't have a typed signature. This prevents a
Expand Down Expand Up @@ -31,9 +31,6 @@ ignore_missing_imports = True
[mypy-importlib.metadata]
ignore_missing_imports = True

[mypy-importlib_metadata]
ignore_missing_imports = True

[mypy-importlib.resources]
ignore_missing_imports = True

Expand Down
22 changes: 5 additions & 17 deletions nextstrain/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,29 @@ def main():
# rest of the codebase. Avoids needing to instruct folks to set
# PYTHONIOENCODING=UTF-8 or use Python's UTF-8 mode (-X utf8 or
# PYTHONUTF8=1).
sys.stdout = reconfigure_stdio(sys.stdout) # type: ignore[arg-type]
sys.stderr = reconfigure_stdio(sys.stderr) # type: ignore[arg-type]
reconfigure_stdio(sys.stdout) # type: ignore[arg-type]
reconfigure_stdio(sys.stderr) # type: ignore[arg-type]

return cli.run( argv[1:] )


def reconfigure_stdio(stdio: TextIOWrapper) -> TextIOWrapper:
def reconfigure_stdio(stdio: TextIOWrapper):
"""
Reconfigure *stdio* to match the assumptions of this codebase.

Suitable only for output streams (e.g. stdout, stderr), as reconfiguring an
input stream is more complicated.
"""
# XXX TODO: When we drop Python 3.6 support, most of this function can be
# replaced by stdio.reconfigure().
# -trs, 6 June 2022

# Flush any pending output under old configuration.
stdio.flush()

# Configure new text stream on the same underlying buffered byte stream.
return TextIOWrapper(
stdio.buffer,

stdio.reconfigure(
# Always use UTF-8 and be more lenient on stderr so even mangled error
# messages make it out.
encoding = "UTF-8",
errors = "backslashreplace" if stdio is sys.stderr else "strict",

# Explicitly enable universal newlines mode so we do the right thing.
newline = None,

# Preserve line buffering which is set at process start dynamically
# depending on what the stdio is actually attached to.
line_buffering = stdio.line_buffering)
newline = None)


# Run when called as `python -m nextstrain.cli`, here for good measure.
Expand Down
13 changes: 2 additions & 11 deletions nextstrain/cli/aws/cognito/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,8 @@
AWS Cognito helpers.
"""
import boto3
import warnings

# Ignore noisy warning from cryptography 37.0.0 and 39.0.0 about deprecated support for Python 3.6.
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message = "Python 3\\.6 is no longer supported by the Python core team\\. Therefore, support for it is deprecated in cryptography",
category = UserWarning)

import jwt
import jwt.exceptions
import jwt
import jwt.exceptions

from .srp import CognitoSRP, NewPasswordRequiredError # noqa: F401 (NewPasswordRequiredError is for re-export)

Expand Down
4 changes: 0 additions & 4 deletions nextstrain/cli/command/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,6 @@ def parse_snakemake_args(args):
>>> sorted(parse_snakemake_args([]).items())
[('--cores', []), ('--resources', [])]
"""
# XXX TODO: Consider using a small ArgumentParser() for this in the
# future, when we can require Python 3.7 and use parse_intermixed_args().
# -trs, 20 May 2020

opts = {
"-j" if re.search(r"^-j\d+$", arg) else arg
for arg in map(lambda arg: arg.split("=", 1)[0], args)
Expand Down
10 changes: 1 addition & 9 deletions nextstrain/cli/util.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
try:
from importlib.metadata import distribution as distribution_info, PackageNotFoundError
except ModuleNotFoundError:
from importlib_metadata import distribution as distribution_info, PackageNotFoundError

import os
import platform
import re
Expand All @@ -11,6 +6,7 @@
import subprocess
import sys
from functools import partial
from importlib.metadata import distribution as distribution_info, PackageNotFoundError
from typing import Any, Callable, Iterable, Mapping, List, Optional, Sequence, Tuple, Union, overload
# TODO: Use typing.Literal once Python 3.8 is the minimum supported version.
from typing_extensions import Literal
Expand Down Expand Up @@ -271,10 +267,6 @@ def capture_output(argv, extra_env: Mapping = {}):
Run the command specified by the argument list and return a list of output
lines.

This wrapper around subprocess.run() exists because its own capture_output
parameter wasn't added until Python 3.7 and we aim for compat with 3.6.
When we bump our minimum Python version, we can remove this wrapper.

If an *extra_env* mapping is passed, the provided keys and values are
overlayed onto the current environment. Keys with a value of ``None`` are
removed from the current environment (i.e. like ``del os.environ[key]``).
Expand Down
2 changes: 1 addition & 1 deletion pyrightconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"pythonVersion": "3.6",
"pythonVersion": "3.8",
"include": ["nextstrain"],
"ignore": [
"nextstrain/cli/markdown.py",
Expand Down
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ def find_namespaced_packages(namespace):

# Python 3 only
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
],

# Install a "nextstrain" program which calls nextstrain.cli.__main__.main()
Expand All @@ -81,13 +83,11 @@ def find_namespaced_packages(namespace):
],
},

python_requires = '>=3.6',
python_requires = '>=3.8',

install_requires = [
"dataclasses; python_version < '3.7'",
"docutils",
"fasteners",
"importlib_metadata; python_version < '3.8'",
"importlib_resources >=5.3.0; python_version < '3.11'",
"packaging",
"pyjwt[crypto] >=2.0.0",
Expand Down