Skip to content

Commit

Permalink
Drop support for Python 3.7 (#10009)
Browse files Browse the repository at this point in the history
* Drop support for Python 3.7

This updates our documentation and build processes to set Python 3.8 as
the oldest support version of Python, consistent with our policy on
Python support.

This commit also removes remaining Python-version gating, since we were
principally using this to account for differences between 3.7 and 3.8.
Several backport packages are no longer required for any suppported
Python version, because of this change.

* Remove test for multiprocessing on Mac

With Python 3.7 support now dropped, there are no versions of Python on
macOS that we expect to support with multiprocessing again.  There's no
guarantee that the hypothetical Python 10.11 (???) that this test was
previously checking would be any more valid than existing versions.

---------

Co-authored-by: Matthew Treinish <[email protected]>
  • Loading branch information
jakelishman and mtreinish authored May 5, 2023
1 parent 72e7481 commit 4dfef13
Show file tree
Hide file tree
Showing 27 changed files with 45 additions and 134 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/setup-python@v4
name: Install Python
with:
python-version: '3.7'
python-version: '3.10'
- uses: dtolnay/rust-toolchain@stable
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
- uses: actions/setup-python@v4
name: Install Python
with:
python-version: '3.7'
python-version: '3.10'
- uses: dtolnay/rust-toolchain@stable
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
Expand Down Expand Up @@ -83,7 +83,7 @@ jobs:
- uses: actions/setup-python@v4
name: Install Python
with:
python-version: '3.7'
python-version: '3.10'
- uses: dtolnay/rust-toolchain@stable
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
Expand Down
14 changes: 7 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,12 @@ environment that tox sets up matches the CI environment more closely and it
runs the tests in parallel (resulting in much faster execution). To run tests
on all installed supported python versions and lint/style checks you can simply
run `tox`. Or if you just want to run the tests once run for a specific python
version: `tox -epy37` (or replace py37 with the python version you want to use,
py35 or py36).
version: `tox -epy310` (or replace py310 with the python version you want to use,
py39 or py311).

If you just want to run a subset of tests you can pass a selection regex to
the test runner. For example, if you want to run all tests that have "dag" in
the test id you can run: `tox -epy37 -- dag`. You can pass arguments directly to
the test id you can run: `tox -epy310 -- dag`. You can pass arguments directly to
the test runner after the bare `--`. To see all the options on test selection
you can refer to the stestr manual:
https://stestr.readthedocs.io/en/stable/MANUAL.html#test-selection
Expand All @@ -291,21 +291,21 @@ you can do this faster with the `-n`/`--no-discover` option. For example:

to run a module:
```
tox -epy37 -- -n test.python.test_examples
tox -epy310 -- -n test.python.test_examples
```
or to run the same module by path:

```
tox -epy37 -- -n test/python/test_examples.py
tox -epy310 -- -n test/python/test_examples.py
```
to run a class:

```
tox -epy37 -- -n test.python.test_examples.TestPythonExamples
tox -epy310 -- -n test.python.test_examples.TestPythonExamples
```
to run a method:
```
tox -epy37 -- -n test.python.test_examples.TestPythonExamples.test_all_examples
tox -epy310 -- -n test.python.test_examples.TestPythonExamples.test_all_examples
```

Alternatively there is a makefile provided to run tests, however this
Expand Down
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ parameters:
- name: "supportedPythonVersions"
displayName: "All supported versions of Python"
type: object
default: ["3.7", "3.8", "3.9", "3.10", "3.11"]
default: ["3.8", "3.9", "3.10", "3.11"]

- name: "minimumPythonVersion"
displayName: "Minimum supported version of Python"
type: string
default: "3.7"
default: "3.8"

- name: "maximumPythonVersion"
displayName: "Maximum supported version of Python"
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"

[tool.black]
line-length = 100
target-version = ['py37', 'py38', 'py39', 'py310', 'py311']
target-version = ['py38', 'py39', 'py310', 'py311']

[tool.cibuildwheel]
manylinux-x86_64-image = "manylinux2014"
manylinux-i686-image = "manylinux2014"
skip = "pp* cp36-* *musllinux*"
skip = "pp* cp36-* cp37-* *musllinux*"
test-skip = "cp310-win32 cp310-manylinux_i686 cp311-win32 cp311-manylinux_i686"
test-command = "python {project}/examples/python/stochastic_swap.py"
# We need to use pre-built versions of Numpy and Scipy in the tests; they have a
Expand Down
9 changes: 0 additions & 9 deletions qiskit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@
import qiskit._accelerate


if sys.version_info < (3, 8):
warnings.warn(
"Using Qiskit with Python 3.7 is deprecated as of the 0.23.0 release. "
"Support for running Qiskit with Python 3.7 will be removed in the "
"0.25.0 release",
DeprecationWarning,
)


# Globally define compiled submodules. The normal import mechanism will not find compiled submodules
# in _accelerate because it relies on file paths, but PyO3 generates only one shared library file.
# We manually define them on import so people can directly import qiskit._accelerate.* submodules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

from __future__ import annotations

import sys
from collections.abc import Sequence
from typing import Literal

import numpy as np

Expand All @@ -30,11 +30,6 @@

from ..exceptions import AlgorithmError

if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal


class FiniteDiffEstimatorGradient(BaseEstimatorGradient):
"""
Expand Down
8 changes: 1 addition & 7 deletions qiskit/algorithms/gradients/finite_diff_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

from __future__ import annotations

import sys
from collections import defaultdict
from typing import Literal, Sequence

import numpy as np

Expand All @@ -28,12 +28,6 @@

from ..exceptions import AlgorithmError

if sys.version_info >= (3, 8):
# pylint: disable=ungrouped-imports
from typing import Literal, Sequence
else:
from typing_extensions import Literal


class FiniteDiffSamplerGradient(BaseSamplerGradient):
"""
Expand Down
9 changes: 1 addition & 8 deletions qiskit/algorithms/optimizers/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,13 @@
from collections.abc import Callable
from enum import IntEnum
import logging
import sys
from typing import Any, Union
from typing import Any, Union, Protocol

import numpy as np
import scipy

from qiskit.algorithms.algorithm_result import AlgorithmResult

if sys.version_info >= (3, 8):
# pylint: disable=ungrouped-imports
from typing import Protocol
else:
from typing_extensions import Protocol

logger = logging.getLogger(__name__)

POINT = Union[float, np.ndarray]
Expand Down
12 changes: 5 additions & 7 deletions qiskit/algorithms/optimizers/p_bfgs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import logging
import multiprocessing
import platform
import sys
from collections.abc import Callable
from typing import SupportsFloat

Expand Down Expand Up @@ -109,12 +108,11 @@ def minimize(
# default. The fork start method should be considered unsafe as it can
# lead to crashes.
# However P_BFGS doesn't support spawn, so we revert to single process.
if sys.version_info >= (3, 8):
num_procs = 0
logger.warning(
"For MacOS, python >= 3.8, using only current process. "
"Multiple core use not supported."
)
num_procs = 0
logger.warning(
"For MacOS, python >= 3.8, using only current process. "
"Multiple core use not supported."
)
elif platform.system() == "Windows":
num_procs = 0
logger.warning(
Expand Down
8 changes: 1 addition & 7 deletions qiskit/circuit/controlflow/switch_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
__all__ = ("SwitchCaseOp", "CASE_DEFAULT")

import contextlib
import sys
from typing import Union, Iterable, Any, Tuple, Optional, List
from typing import Union, Iterable, Any, Tuple, Optional, List, Literal

from qiskit.circuit import ClassicalRegister, Clbit, QuantumCircuit
from qiskit.circuit.exceptions import CircuitError
Expand All @@ -25,11 +24,6 @@
from .control_flow import ControlFlowOp
from ._builder_utils import unify_circuit_resources, partition_registers

if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal


class _DefaultCaseType:
"""The type of the default-case singleton. This is used instead of just having
Expand Down
9 changes: 2 additions & 7 deletions qiskit/compiler/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
import logging
import os
import pickle
import sys
from time import time
from typing import List, Union, Dict, Callable, Any, Optional, Tuple, Iterable, TypeVar
from multiprocessing.shared_memory import SharedMemory
from multiprocessing.managers import SharedMemoryManager
import warnings

from qiskit import user_config
Expand All @@ -48,12 +49,6 @@
from qiskit.transpiler.timing_constraints import TimingConstraints
from qiskit.transpiler.target import Target, target_to_backend_properties

if sys.version_info >= (3, 8):
from multiprocessing.shared_memory import SharedMemory
from multiprocessing.managers import SharedMemoryManager
else:
from shared_memory import SharedMemory, SharedMemoryManager

logger = logging.getLogger(__name__)

_CircuitT = TypeVar("_CircuitT", bound=Union[QuantumCircuit, List[QuantumCircuit]])
Expand Down
7 changes: 1 addition & 6 deletions qiskit/pulse/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,10 @@
import contextvars
import functools
import itertools
import sys
import uuid
import warnings
from contextlib import contextmanager
from functools import singledispatchmethod
from typing import (
Any,
Callable,
Expand Down Expand Up @@ -499,11 +499,6 @@
from qiskit.pulse.schedule import Schedule, ScheduleBlock
from qiskit.pulse.transforms.alignments import AlignmentKind

if sys.version_info >= (3, 8):
from functools import singledispatchmethod
else:
from singledispatchmethod import singledispatchmethod


#: contextvars.ContextVar[BuilderContext]: active builder
BUILDER_CONTEXTVAR = contextvars.ContextVar("backend")
Expand Down
8 changes: 1 addition & 7 deletions qiskit/qasm2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,8 @@ def from_qasm_str(qasm_str: str):
]

import os
import sys
from pathlib import Path
from typing import Iterable, Union, Optional
from typing import Iterable, Union, Optional, Literal

# Pylint can't handle the C-extension introspection of `_qasm2` because there's a re-import through
# to `qiskit.qasm2.exceptions`, and pylint ends up trying to import `_qasm2` twice, which PyO3
Expand All @@ -405,11 +404,6 @@ def from_qasm_str(qasm_str: str):
LEGACY_CUSTOM_CLASSICAL,
)

if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal


LEGACY_INCLUDE_PATH = (
Path(__file__).parents[1] / "qasm" / "libs",
Expand Down
7 changes: 1 addition & 6 deletions qiskit/qobj/converters/pulse_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

import hashlib
import re
import sys
import warnings
from enum import Enum
from functools import singledispatchmethod
from typing import Union, List, Iterator, Optional
import numpy as np

Expand All @@ -32,11 +32,6 @@
from qiskit.qobj.utils import MeasLevel
from qiskit.utils.deprecation import deprecate_func

if sys.version_info >= (3, 8):
from functools import singledispatchmethod
else:
from singledispatchmethod import singledispatchmethod


class ParametricPulseShapes(Enum):
"""Map the assembled pulse names to the pulse module waveforms.
Expand Down
5 changes: 1 addition & 4 deletions qiskit/tools/parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,7 @@ def get_platform_parallel_default():
parallel_default = False
# On macOS default false on Python >=3.8
elif sys.platform == "darwin":
if sys.version_info[0] == 3 and sys.version_info[1] >= 8:
parallel_default = False
else:
parallel_default = True
parallel_default = False
# On linux (and other OSes) default to True
else:
parallel_default = True
Expand Down
7 changes: 1 addition & 6 deletions qiskit/transpiler/passes/basis/basis_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

"""Translates gates to a target basis using a given equivalence library."""

import sys
import time
import logging

from functools import singledispatchmethod
from itertools import zip_longest
from collections import defaultdict

Expand All @@ -29,11 +29,6 @@
from qiskit.transpiler.basepasses import TransformationPass
from qiskit.transpiler.exceptions import TranspilerError

if sys.version_info >= (3, 8):
from functools import singledispatchmethod
else:
from singledispatchmethod import singledispatchmethod

logger = logging.getLogger(__name__)


Expand Down
13 changes: 2 additions & 11 deletions qiskit/utils/multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import multiprocessing as mp
import platform
import sys

import psutil

Expand Down Expand Up @@ -44,14 +43,6 @@ def is_main_process():
if platform.system() == "Windows":
return not isinstance(mp.current_process(), mp.context.SpawnProcess)
else:
return not (
isinstance(mp.current_process(), (mp.context.ForkProcess, mp.context.SpawnProcess))
# In python 3.5 and 3.6, processes created by "ProcessPoolExecutor" are not
# mp.context.ForkProcess or mp.context.SpawnProcess. As a workaround,
# "name" of the process is checked instead.
or (
sys.version_info[0] == 3
and (sys.version_info[1] == 5 or sys.version_info[1] == 6)
and mp.current_process().name != "MainProcess"
)
return not isinstance(
mp.current_process(), (mp.context.ForkProcess, mp.context.SpawnProcess)
)
Loading

0 comments on commit 4dfef13

Please sign in to comment.