Skip to content

Commit

Permalink
Move build configuration to static configuration files
Browse files Browse the repository at this point in the history
This removes the vast majority of the dynamic code from our `setup.py`
files, and instead uses static configuration to specify them.  As part
of this, we also use a single `VERSION.txt` as a single source of truth
for both the `qiskit-terra` main package and the `qiskit` "metapackage".
This should avoid a situation where we let the two get out of sync
during a release, which can cause us severe problems for fixing the
problem with respect to git tags.
  • Loading branch information
jakelishman committed Nov 28, 2023
1 parent 7f809a9 commit 651e51b
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 176 deletions.
128 changes: 128 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,134 @@
requires = ["setuptools", "wheel", "setuptools-rust"]
build-backend = "setuptools.build_meta"

[project]
name = "qiskit"
description = "An open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives."
requires-python = ">=3.8"
license = { file = "LICENSE.txt" }
authors = [
{ name = "Qiskit Development Team", email = "[email protected]" },
]
keywords = [
"qiskit",
"quantum circuit",
"quantum computing",
"quantum programming language",
"quantum",
"sdk",
]
classifiers = [
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: Apache Software License",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Scientific/Engineering",
]
# These are configured in the `tool.setuptools.dynamic` table.
dynamic = ["version", "readme", "dependencies"]

# If modifying this table, be sure to sync with `requirements-optional.txt`,
# `qiskit.utils.optionals`, and `qiskit_pkg`'s `pyproject.toml` too.
[project.optional-dependencies]
qasm3-import = [
"qiskit-qasm3-import >= 0.1.0",
]
visualization = [
"matplotlib >= 3.3",
"ipywidgets >= 7.3.0",
"pydot",
"Pillow >= 4.2.1",
"pylatexenc >= 1.4",
"seaborn >= 0.9.0",
"pygments >= 2.4",
]
crosstalk-pass = [
"z3-solver >= 4.7",
]
csp-layout-pass = [
"python-constraint >= 1.4",
]
# This will make the resolution work for installers from PyPI, but `pip install .[all]` will be
# unreliable because `qiskit-terra` will resolve to the PyPI version, so local changes in the
# optionals won't be reflected.
all = ["qiskit[qasm3-import,visualization,crosstalk-pass,csp-layout-pass]"]

[project.urls]
Homepage = "https://qiskit.org"
Documentation = "https://qiskit.org/documentation"
"Source Code" = "https://github.com/Qiskit/qiskit"
"Bug Tracker" = "https://github.com/Qiskit/qiskit/issues"
Changelog = "https://qiskit.org/documentation/release_notes.html"

[project.entry-points."qiskit.unitary_synthesis"]
default = "qiskit.transpiler.passes.synthesis.unitary_synthesis:DefaultUnitarySynthesis"
aqc = "qiskit.transpiler.synthesis.aqc.aqc_plugin:AQCSynthesisPlugin"
sk = "qiskit.transpiler.passes.synthesis.solovay_kitaev_synthesis:SolovayKitaevSynthesis"

[project.entry-points."qiskit.synthesis"]
"clifford.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisClifford"
"clifford.ag" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:AGSynthesisClifford"
"clifford.bm" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BMSynthesisClifford"
"clifford.greedy" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:GreedySynthesisClifford"
"clifford.layers" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerSynthesisClifford"
"clifford.lnn" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerLnnSynthesisClifford"
"linear_function.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisLinearFunction"
"linear_function.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisLinearFunction"
"linear_function.pmh" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:PMHSynthesisLinearFunction"
"permutation.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation"
"permutation.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisPermutation"
"permutation.basic" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation"
"permutation.acg" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:ACGSynthesisPermutation"

[project.entry-points."qiskit.transpiler.init"]
default = "qiskit.transpiler.preset_passmanagers.builtin_plugins:DefaultInitPassManager"

[project.entry-points."qiskit.transpiler.translation"]
synthesis = "qiskit.transpiler.preset_passmanagers.builtin_plugins:UnitarySynthesisPassManager"
translator = "qiskit.transpiler.preset_passmanagers.builtin_plugins:BasisTranslatorPassManager"
unroller = "qiskit.transpiler.preset_passmanagers.builtin_plugins:UnrollerPassManager"

[project.entry-points."qiskit.transpiler.routing"]
basic = "qiskit.transpiler.preset_passmanagers.builtin_plugins:BasicSwapPassManager"
lookahead = "qiskit.transpiler.preset_passmanagers.builtin_plugins:LookaheadSwapPassManager"
none = "qiskit.transpiler.preset_passmanagers.builtin_plugins:NoneRoutingPassManager"
sabre = "qiskit.transpiler.preset_passmanagers.builtin_plugins:SabreSwapPassManager"
stochastic = "qiskit.transpiler.preset_passmanagers.builtin_plugins:StochasticSwapPassManager"

[project.entry-points."qiskit.transpiler.optimization"]
default = "qiskit.transpiler.preset_passmanagers.builtin_plugins:OptimizationPassManager"

[project.entry-points."qiskit.transpiler.layout"]
default = "qiskit.transpiler.preset_passmanagers.builtin_plugins:DefaultLayoutPassManager"
dense = "qiskit.transpiler.preset_passmanagers.builtin_plugins:DenseLayoutPassManager"
noise_adaptive = "qiskit.transpiler.preset_passmanagers.builtin_plugins:NoiseAdaptiveLayoutPassManager"
sabre = "qiskit.transpiler.preset_passmanagers.builtin_plugins:SabreLayoutPassManager"
trivial = "qiskit.transpiler.preset_passmanagers.builtin_plugins:TrivialLayoutPassManager"

[project.entry-points."qiskit.transpiler.scheduling"]
alap = "qiskit.transpiler.preset_passmanagers.builtin_plugins:AlapSchedulingPassManager"
asap = "qiskit.transpiler.preset_passmanagers.builtin_plugins:AsapSchedulingPassManager"
default = "qiskit.transpiler.preset_passmanagers.builtin_plugins:DefaultSchedulingPassManager"

[tool.setuptools]
include-package-data = true

[tool.setuptools.dynamic]
version = { file = "qiskit/VERSION.txt" }
readme = { file = "README.md", content-type = "text/markdown" }
dependencies = {file = "requirements.txt" }

[tool.setuptools.packages.find]
include = ["qiskit", "qiskit.*"]

[tool.black]
line-length = 100
target-version = ['py38', 'py39', 'py310', 'py311']
Expand Down
4 changes: 2 additions & 2 deletions qiskit/transpiler/passes/synthesis/high_level_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class HLSConfig:
hls_config = HLSConfig(permutation=[(ACGSynthesisPermutation(), {})])
hls_config = HLSConfig(permutation=[ACGSynthesisPermutation()])
The names of the synthesis algorithms should be declared in ``entry_points`` for
``qiskit.synthesis`` in ``setup.py``, in the form
The names of the synthesis algorithms should be declared in ``entry-points`` table for
``qiskit.synthesis`` in ``pyproject.toml``, in the form
<higher-level-object-name>.<synthesis-method-name>.
The standard higher-level-objects are recommended to have a synthesis method
Expand Down
43 changes: 18 additions & 25 deletions qiskit/transpiler/passes/synthesis/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,15 @@ def run(self, unitary, **options):
The second step is to expose the
:class:`~qiskit.transpiler.passes.synthesis.plugin.UnitarySynthesisPlugin` as
a setuptools entry point in the package metadata. This is done by simply adding
an ``entry_points`` entry to the ``setuptools.setup`` call in the ``setup.py``
for the plugin package with the necessary entry points under the
``qiskit.unitary_synthesis`` namespace. For example::
entry_points = {
'qiskit.unitary_synthesis': [
'special = qiskit_plugin_pkg.module.plugin:SpecialUnitarySynthesis',
]
},
(note that the entry point ``name = path`` is a single string not a Python
expression). There isn't a limit to the number of plugins a single package can
an ``entry-points`` table in ``pyproject.toml`` for the plugin package with the necessary entry
points under the ``qiskit.unitary_synthesis`` namespace. For example:
.. code-block:: toml
[project.entry-points."qiskit.unitary-synthesis"]
"special" = "qiskit_plugin_pkg.module.plugin:SpecialUnitarySynthesis"
There isn't a limit to the number of plugins a single package can
include as long as each plugin has a unique name. So a single package can
expose multiple plugins if necessary. The name ``default`` is used by Qiskit
itself and can't be used in a plugin.
Expand Down Expand Up @@ -218,19 +215,15 @@ def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **
The second step is to expose the
:class:`~qiskit.transpiler.passes.synthesis.plugin.HighLevelSynthesisPlugin` as
a setuptools entry point in the package metadata. This is done by adding
an ``entry_points`` entry to the ``setuptools.setup`` call in the ``setup.py``
for the plugin package with the necessary entry points under the
``qiskit.synthesis`` namespace. For example::
entry_points = {
'qiskit.synthesis': [
'clifford.special = qiskit_plugin_pkg.module.plugin:SpecialSynthesisClifford',
]
},
(note that the entry point ``name = path`` is a single string not a Python
expression). The ``name`` consists of two parts separated by dot ".": the
name of the
an ``entry-points`` table in ``pyproject.toml`` for the plugin package with the necessary entry
points under the ``qiskit.unitary_synthesis`` namespace. For example:
.. code-block:: toml
[project.entry-points."qiskit.synthesis"]
"clifford.special" = "qiskit_plugin_pkg.module.plugin:SpecialSynthesisClifford"
The ``name`` consists of two parts separated by dot ".": the name of the
type of :class:`~qiskit.circuit.Operation` to which the synthesis plugin applies
(``clifford``), and the name of the plugin (``special``).
There isn't a limit to the number of plugins a single package can
Expand Down
30 changes: 13 additions & 17 deletions qiskit/transpiler/preset_passmanagers/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,23 +134,19 @@ def pass_manager(self, pass_manager_config, optimization_level):
The second step is to expose the :class:`~.PassManagerStagePlugin`
subclass as a setuptools entry point in the package metadata. This can be done
by simply adding an ``entry_points`` entry to the ``setuptools.setup`` call in
the ``setup.py`` or the plugin package with the necessary entry points under the
appropriate namespace for the stage your plugin is for. You can see the list
of stages, entry points, and expectations from the stage in :ref:`stage_table`.
For example, continuing from the example plugin above::
entry_points = {
'qiskit.transpiler.layout': [
'vf2 = qiskit_plugin_pkg.module.plugin:VF2LayoutPlugin',
]
},
Note that the entry point ``name = path`` is a single string not a Python
expression. There isn't a limit to the number of plugins a single package can
include as long as each plugin has a unique name. So a single package can
expose multiple plugins if necessary. Refer to :ref:`stage_table` for a list
of reserved names for each stage.
an ``entry-points`` table in ``pyproject.toml`` for the plugin package with the necessary entry
points under the appropriate namespace for the stage your plugin is for. You can see the list of
stages, entry points, and expectations from the stage in :ref:`stage_table`. For example,
continuing from the example plugin above::
.. code-block:: toml
[project.entry-points."qiskit.transpiler.layout"]
"vf2" = "qiskit_plugin_pkg.module.plugin:VF2LayoutPlugin"
There isn't a limit to the number of plugins a single package can include as long as each plugin has
a unique name. So a single package can expose multiple plugins if necessary. Refer to
:ref:`stage_table` for a list of reserved names for each stage.
Plugin API
==========
Expand Down
2 changes: 1 addition & 1 deletion qiskit/utils/optionals.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@
"""

# NOTE: If you're changing this file, sync it with `requirements-optional.txt` and potentially
# `setup.py` as well.
# `pyproject.toml` as well.

import logging as _logging

Expand Down
2 changes: 1 addition & 1 deletion requirements-optional.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# standard pip conventions, even though none of these are required.
#
# If updating this, you probably want to update `qiskit.utils.optionals` and
# maybe `setup.py` too.
# maybe `pyproject.toml` too.

# Test-runner enhancements.
fixtures
Expand Down
Loading

0 comments on commit 651e51b

Please sign in to comment.