From 9dbfa18df42276ccf45eecb51680dc97430220ce Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 6 Aug 2022 10:13:48 +0200 Subject: [PATCH 1/7] pip install, run examples and notebooks in conda-forge base environment --- .github/workflows/install_examples.yml | 29 ++++++++++++-------------- setup.py | 2 +- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/workflows/install_examples.yml b/.github/workflows/install_examples.yml index b36ff3e7f..b1e7adb3c 100644 --- a/.github/workflows/install_examples.yml +++ b/.github/workflows/install_examples.yml @@ -1,4 +1,4 @@ -name: setup.py, examples +name: Setup, Examples, Notebooks on: [push, pull_request] @@ -7,26 +7,23 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - - name: Install Python dependencies + - uses: actions/checkout@v3 + - name: Install Python dependencies from conda-forge run: | - # Set up conda + # Set up conda using the preinstalled GHA conda environment echo $CONDA/bin >> $GITHUB_PATH + conda config --add channels conda-forge + conda config --set channel_priority strict - # Set up (virtual) X11 - sudo apt install -y xvfb + # Install build tools + conda install pip setuptools setuptools-scm - # Install test tools - conda install pip pytest + # Install python-control dependencies and extras + conda install numpy matplotlib scipy + conda install slycot pmw jupyter - # Install python-control dependencies - conda install numpy matplotlib scipy jupyter - conda install -c conda-forge slycot pmw - - - name: Install with setup.py - run: python setup.py install + - name: Install from source + run: pip install . - name: Run examples run: | diff --git a/setup.py b/setup.py index 2021d5eb9..45db2341b 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ exec(fd.read(), ver) version = ver.get('__version__', 'dev') except IOError: - version = 'dev' + version = '0.0.0dev' with open('README.rst') as fp: long_description = fp.read() From 3aeac6189227e4b97a868da33220ff28ab1a965c Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 6 Aug 2022 10:12:06 +0200 Subject: [PATCH 2/7] Build Slycot from source using PyPI wheels --- .github/workflows/control-slycot-src.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/control-slycot-src.yml b/.github/workflows/control-slycot-src.yml index ffbeca3f9..f42de8802 100644 --- a/.github/workflows/control-slycot-src.yml +++ b/.github/workflows/control-slycot-src.yml @@ -15,17 +15,14 @@ jobs: uses: actions/setup-python@v2 - name: Install Python dependencies run: | - # Set up conda - echo $CONDA/bin >> $GITHUB_PATH - # Set up (virtual) X11 sudo apt install -y xvfb # Install test tools - conda install pip pytest pytest-timeout + pip install pytest pytest-timeout # Install python-control dependencies - conda install numpy matplotlib scipy + pip install numpy matplotlib scipy - name: Checkout Slycot uses: actions/checkout@v3 @@ -43,10 +40,9 @@ jobs: # Install compilers, libraries, and development environment sudo apt-get -y install gfortran cmake --fix-missing sudo apt-get -y install libblas-dev liblapack-dev - conda install -c conda-forge scikit-build setuptools-scm # Compile and install slycot - pip install -v --no-build-isolation --no-deps . + pip install -v . - name: Test with pytest working-directory: python-control From 8c963bb306d0039a04c7f130bdc4c1ae73e703cd Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 6 Aug 2022 14:05:18 +0200 Subject: [PATCH 3/7] Modernize build system with PEP517 --- README.rst | 15 +++++-------- make_version.py | 58 ------------------------------------------------- pyproject.toml | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 7 ------ setup.py | 52 -------------------------------------------- 5 files changed, 64 insertions(+), 126 deletions(-) delete mode 100644 make_version.py create mode 100644 pyproject.toml delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/README.rst b/README.rst index f1feda7c5..7e2058293 100644 --- a/README.rst +++ b/README.rst @@ -97,17 +97,14 @@ To install using pip:: If you install Slycot using pip you'll need a development environment (e.g., Python development files, C and Fortran compilers). -Distutils ---------- +Installing from source +---------------------- -To install in your home directory, use:: +To install from source, get the source code of the desired branch or release +from the github repository or archive, unpack, and run from within the +toplevel `python-control` directory:: - python setup.py install --user - -To install for all users (on Linux or Mac OS):: - - python setup.py build - sudo python setup.py install + pip install . Development diff --git a/make_version.py b/make_version.py deleted file mode 100644 index 356f4d747..000000000 --- a/make_version.py +++ /dev/null @@ -1,58 +0,0 @@ -# make_version.py - generate version information -# -# Author: Clancy Rowley -# Date: 2 Apr 2015 -# Modified: Richard M. Murray, 28 Dec 2017 -# -# This script is used to create the version information for the python- -# control package. The version information is now generated directly from -# tags in the git repository. Now, *before* running setup.py, one runs -# -# python make_version.py -# -# and this generates a file with the version information. This is copied -# from binstar (https://github.com/Binstar/binstar) and seems to work well. -# -# The original version of this script also created version information for -# conda, but this stopped working when conda v3 was released. Instead, we -# now use jinja templates in conda-recipe to create the conda information. -# The current version information is used in setup.py, control/__init__.py, -# and doc/conf.py (for sphinx). - -from subprocess import check_output -import os - -def main(): - cmd = 'git describe --always --long' - # describe --long usually outputs "tag-numberofcommits-commitname" - output = check_output(cmd.split()).decode('utf-8').strip().rsplit('-',2) - if len(output) == 3: - version, build, commit = output - else: - # If the clone is shallow, describe's output won't have tag and - # number of commits. This is a particular issue on Travis-CI, - # which by default clones with a depth of 50. - # This behaviour isn't well documented in git-describe docs, - # but see, e.g., https://stackoverflow.com/a/36389573/1008142 - # and https://github.com/travis-ci/travis-ci/issues/3412 - version = 'unknown' - build = 'unknown' - # we don't ever expect just one dash from describe --long, but - # just in case: - commit = '-'.join(output) - - print("Version: %s" % version) - print("Build: %s" % build) - print("Commit: %s\n" % commit) - - filename = "control/_version.py" - print("Writing %s" % filename) - with open(filename, 'w') as fd: - if build == '0': - fd.write('__version__ = "%s"\n' % (version)) - else: - fd.write('__version__ = "%s.post%s"\n' % (version, build)) - fd.write('__commit__ = "%s"\n' % (commit)) - -if __name__ == '__main__': - main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..89690ac8d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,58 @@ +[build-system] +requires = [ + "setuptools", + "setuptools-scm", + "wheel" +] +build-backend = "setuptools.build_meta" + +[project] +name = "control" +description = "Python Control Systems Library" +authors = [{name = "Python Control Developers", email = "python-control-developers@lists.sourceforge.net"}] +license = {text = "BSD-3-Clause"} +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Software Development", + "Topic :: Scientific/Engineering", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS", +] +requires-python = ">=3.7" +dependencies = [ + "numpy", + "scipy>=1.3", + "matplotlib", +] +dynamic = ["version"] + +[tool.setuptools] +packages = ["control"] + +[project.optional-dependencies] +test = ["pytest", "pytest-timeout"] +slycot = [ "slycot>=0.4.0" ] +cvxopt = [ "cvxopt>=1.2.0" ] + +[project.urls] +homepage = "https//python-control.org" +source = "https://github.com/python-control/python-control" + +[tool.setuptools_scm] +write_to = "control/_version.py" + +[tool.pytest.ini_options] +addopts = "-ra" +filterwarnings = [ + "error:.*matrix subclass:PendingDeprecationWarning", +] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 5b1ce28a7..000000000 --- a/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[bdist_wheel] -universal=1 - -[tool:pytest] -addopts = -ra -filterwarnings = - error:.*matrix subclass:PendingDeprecationWarning diff --git a/setup.py b/setup.py deleted file mode 100644 index 45db2341b..000000000 --- a/setup.py +++ /dev/null @@ -1,52 +0,0 @@ -from setuptools import setup, find_packages - -ver = {} -try: - with open('control/_version.py') as fd: - exec(fd.read(), ver) - version = ver.get('__version__', 'dev') -except IOError: - version = '0.0.0dev' - -with open('README.rst') as fp: - long_description = fp.read() - -CLASSIFIERS = """ -Development Status :: 3 - Alpha -Intended Audience :: Science/Research -Intended Audience :: Developers -License :: OSI Approved :: BSD License -Programming Language :: Python :: 3 -Programming Language :: Python :: 3.7 -Programming Language :: Python :: 3.8 -Programming Language :: Python :: 3.9 -Topic :: Software Development -Topic :: Scientific/Engineering -Operating System :: Microsoft :: Windows -Operating System :: POSIX -Operating System :: Unix -Operating System :: MacOS -""" - -setup( - name='control', - version=version, - author='Python Control Developers', - author_email='python-control-developers@lists.sourceforge.net', - url='http://python-control.org', - project_urls={ - 'Source': 'https://github.com/python-control/python-control', - }, - description='Python Control Systems Library', - long_description=long_description, - packages=find_packages(exclude=['benchmarks']), - classifiers=[f for f in CLASSIFIERS.split('\n') if f], - install_requires=['numpy', - 'scipy>=1.3', - 'matplotlib'], - extras_require={ - 'test': ['pytest', 'pytest-timeout'], - 'slycot': [ 'slycot>=0.4.0' ], - 'cvxopt': [ 'cvxopt>=1.2.0' ] - } -) From bfb591b702986fe5e5f3b8aba9cb8c6c17755373 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 6 Aug 2022 10:17:03 +0200 Subject: [PATCH 4/7] Bump upper tested version to Python 3.10 --- .github/conda-env/test-env.yml | 2 +- .github/workflows/python-package-conda.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/conda-env/test-env.yml b/.github/conda-env/test-env.yml index cc91a1ade..adaf685cf 100644 --- a/.github/conda-env/test-env.yml +++ b/.github/conda-env/test-env.yml @@ -8,4 +8,4 @@ dependencies: - pytest-timeout - numpy - matplotlib - - scipy \ No newline at end of file + - scipy diff --git a/.github/workflows/python-package-conda.yml b/.github/workflows/python-package-conda.yml index 4e287b45a..c2bf21bce 100644 --- a/.github/workflows/python-package-conda.yml +++ b/.github/workflows/python-package-conda.yml @@ -8,20 +8,20 @@ jobs: Py${{ matrix.python-version }}; ${{ matrix.slycot || 'no' }} Slycot; ${{ matrix.pandas || 'no' }} Pandas; - ${{ matrix.cvxopt || 'no' }} CVXOPT; + ${{ matrix.cvxopt || 'no' }} CVXOPT ${{ matrix.array-and-matrix == 1 && '; array and matrix' || '' }} runs-on: ubuntu-latest strategy: max-parallel: 5 matrix: - python-version: [3.7, 3.9] + python-version: ['3.7', '3.10'] slycot: ["", "conda"] pandas: [""] cvxopt: ["", "conda"] array-and-matrix: [0] include: - - python-version: 3.9 + - python-version: '3.10' slycot: conda pandas: conda array-and-matrix: 1 @@ -55,7 +55,7 @@ jobs: mamba install pandas fi if [[ '${{matrix.cvxopt}}' == 'conda' ]]; then - mamba install cvxopt + mamba install cvxopt fi - name: Test with pytest From 9fc6005f3de9e910fc5c61ce156cf40160b1ee85 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 20 Aug 2022 12:48:38 +0200 Subject: [PATCH 5/7] don't fail fast --- .github/workflows/python-package-conda.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-package-conda.yml b/.github/workflows/python-package-conda.yml index c2bf21bce..fb924d39c 100644 --- a/.github/workflows/python-package-conda.yml +++ b/.github/workflows/python-package-conda.yml @@ -14,6 +14,7 @@ jobs: strategy: max-parallel: 5 + fail-fast: false matrix: python-version: ['3.7', '3.10'] slycot: ["", "conda"] From e8fd49e3bca517959a1532555253cf69a184eaf5 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 6 Aug 2022 12:00:57 +0200 Subject: [PATCH 6/7] Use pytest-xvfb in conda and enforce QtAgg only in one run --- .github/conda-env/test-env.yml | 1 + .github/workflows/control-slycot-src.yml | 14 +++----------- .github/workflows/install_examples.yml | 2 +- .github/workflows/python-package-conda.yml | 11 ++++++----- control/tests/rlocus_test.py | 2 ++ control/tests/sisotool_test.py | 4 ++++ 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/conda-env/test-env.yml b/.github/conda-env/test-env.yml index adaf685cf..a4944f768 100644 --- a/.github/conda-env/test-env.yml +++ b/.github/conda-env/test-env.yml @@ -6,6 +6,7 @@ dependencies: - pytest - pytest-cov - pytest-timeout + - pytest-xvfb - numpy - matplotlib - scipy diff --git a/.github/workflows/control-slycot-src.yml b/.github/workflows/control-slycot-src.yml index f42de8802..2ce2a11dd 100644 --- a/.github/workflows/control-slycot-src.yml +++ b/.github/workflows/control-slycot-src.yml @@ -13,16 +13,8 @@ jobs: path: python-control - name: Set up Python uses: actions/setup-python@v2 - - name: Install Python dependencies - run: | - # Set up (virtual) X11 - sudo apt install -y xvfb - - # Install test tools - pip install pytest pytest-timeout - - # Install python-control dependencies - pip install numpy matplotlib scipy + - name: Install Python dependencies and test tools + run: pip install -v -e './python-control[test]' - name: Checkout Slycot uses: actions/checkout@v3 @@ -46,4 +38,4 @@ jobs: - name: Test with pytest working-directory: python-control - run: xvfb-run --auto-servernum pytest control/tests + run: pytest -v control/tests diff --git a/.github/workflows/install_examples.yml b/.github/workflows/install_examples.yml index b1e7adb3c..84cd706f5 100644 --- a/.github/workflows/install_examples.yml +++ b/.github/workflows/install_examples.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - name: Install Python dependencies from conda-forge run: | - # Set up conda using the preinstalled GHA conda environment + # Set up conda using the preinstalled GHA Miniconda environment echo $CONDA/bin >> $GITHUB_PATH conda config --add channels conda-forge conda config --set channel_priority strict diff --git a/.github/workflows/python-package-conda.yml b/.github/workflows/python-package-conda.yml index fb924d39c..ae889fd05 100644 --- a/.github/workflows/python-package-conda.yml +++ b/.github/workflows/python-package-conda.yml @@ -10,6 +10,7 @@ jobs: ${{ matrix.pandas || 'no' }} Pandas; ${{ matrix.cvxopt || 'no' }} CVXOPT ${{ matrix.array-and-matrix == 1 && '; array and matrix' || '' }} + ${{ matrix.mplbackend && format('; {0}', matrix.mplbackend) }} runs-on: ubuntu-latest strategy: @@ -20,19 +21,19 @@ jobs: slycot: ["", "conda"] pandas: [""] cvxopt: ["", "conda"] + mplbackend: [""] array-and-matrix: [0] include: - python-version: '3.10' slycot: conda pandas: conda + cvxopt: conda + mplbackend: QtAgg array-and-matrix: 1 steps: - uses: actions/checkout@v3 - - name: Set up (virtual) X11 - run: sudo apt install -y xvfb - - name: Setup Conda uses: conda-incubator/setup-miniconda@v2 with: @@ -63,8 +64,8 @@ jobs: shell: bash -l {0} env: PYTHON_CONTROL_ARRAY_AND_MATRIX: ${{ matrix.array-and-matrix }} - run: | - xvfb-run --auto-servernum pytest --cov=control --cov-config=.coveragerc control/tests + MPLBACKEND: ${{ matrix.mplbackend }} + run: pytest -v --cov=control --cov-config=.coveragerc control/tests - name: Coveralls parallel # https://github.com/coverallsapp/github-action diff --git a/control/tests/rlocus_test.py b/control/tests/rlocus_test.py index a0ecebb15..4fbe70c4f 100644 --- a/control/tests/rlocus_test.py +++ b/control/tests/rlocus_test.py @@ -85,6 +85,8 @@ def test_root_locus_neg_false_gain_nonproper(self): # TODO: cover and validate negative false_gain branch in _default_gains() + @pytest.mark.skipif(plt.get_current_fig_manager().toolbar is None, + reason="Requires the zoom toolbar") def test_root_locus_zoom(self): """Check the zooming functionality of the Root locus plot""" system = TransferFunction([1000], [1, 25, 100, 0]) diff --git a/control/tests/sisotool_test.py b/control/tests/sisotool_test.py index d5e9dd013..a1f468eea 100644 --- a/control/tests/sisotool_test.py +++ b/control/tests/sisotool_test.py @@ -46,6 +46,8 @@ def sys221(self): D221 = [[1., -1.]] return StateSpace(A222, B222, C221, D221) + @pytest.mark.skipif(plt.get_current_fig_manager().toolbar is None, + reason="Requires the zoom toolbar") def test_sisotool(self, tsys): sisotool(tsys, Hz=False) fig = plt.gcf() @@ -114,6 +116,8 @@ def test_sisotool(self, tsys): assert_array_almost_equal( ax_step.lines[0].get_data()[1][:10], step_response_moved, 4) + @pytest.mark.skipif(plt.get_current_fig_manager().toolbar is None, + reason="Requires the zoom toolbar") @pytest.mark.parametrize('tsys', [0, True], indirect=True, ids=['ctime', 'dtime']) def test_sisotool_tvect(self, tsys): From 69fb34a462015193d514ea881001b503553f2493 Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Sat, 20 Aug 2022 12:03:36 +0200 Subject: [PATCH 7/7] Replace mplcleanup decorator use by fixture --- control/tests/config_test.py | 20 ++++++-------------- control/tests/conftest.py | 14 ++++++-------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/control/tests/config_test.py b/control/tests/config_test.py index 295c68bdd..c36f67280 100644 --- a/control/tests/config_test.py +++ b/control/tests/config_test.py @@ -8,7 +8,6 @@ from math import pi, log10 import matplotlib.pyplot as plt -from matplotlib.testing.decorators import cleanup as mplcleanup import numpy as np import pytest @@ -18,7 +17,6 @@ @pytest.mark.usefixtures("editsdefaults") # makes sure to reset the defaults # to the test configuration class TestConfig: - # Create a simple second order system to use for testing sys = ct.tf([10], [1, 2, 1]) @@ -28,8 +26,7 @@ def test_set_defaults(self): assert ct.config.defaults['freqplot.deg'] == 2 assert ct.config.defaults['freqplot.Hz'] is None - @mplcleanup - def test_get_param(self): + def test_get_param(self, mplcleanup): assert ct.config._get_param('freqplot', 'dB')\ == ct.config.defaults['freqplot.dB'] assert ct.config._get_param('freqplot', 'dB', 1) == 1 @@ -92,8 +89,7 @@ def test_default_deprecation(self): assert ct.config.defaults['bode.Hz'] \ == ct.config.defaults['freqplot.Hz'] - @mplcleanup - def test_fbs_bode(self): + def test_fbs_bode(self, mplcleanup): ct.use_fbs_defaults() # Generate a Bode plot @@ -137,8 +133,7 @@ def test_fbs_bode(self): phase_x, phase_y = (((plt.gcf().axes[1]).get_lines())[0]).get_data() np.testing.assert_almost_equal(phase_y[-1], -pi, decimal=2) - @mplcleanup - def test_matlab_bode(self): + def test_matlab_bode(self, mplcleanup): ct.use_matlab_defaults() # Generate a Bode plot @@ -182,8 +177,7 @@ def test_matlab_bode(self): phase_x, phase_y = (((plt.gcf().axes[1]).get_lines())[0]).get_data() np.testing.assert_almost_equal(phase_y[-1], -pi, decimal=2) - @mplcleanup - def test_custom_bode_default(self): + def test_custom_bode_default(self, mplcleanup): ct.config.defaults['freqplot.dB'] = True ct.config.defaults['freqplot.deg'] = True ct.config.defaults['freqplot.Hz'] = True @@ -204,8 +198,7 @@ def test_custom_bode_default(self): np.testing.assert_almost_equal(mag_y[0], 20*log10(10), decimal=3) np.testing.assert_almost_equal(phase_y[-1], -pi, decimal=2) - @mplcleanup - def test_bode_number_of_samples(self): + def test_bode_number_of_samples(self, mplcleanup): # Set the number of samples (default is 50, from np.logspace) mag_ret, phase_ret, omega_ret = ct.bode_plot(self.sys, omega_num=87) assert len(mag_ret) == 87 @@ -219,8 +212,7 @@ def test_bode_number_of_samples(self): mag_ret, phase_ret, omega_ret = ct.bode_plot(self.sys, omega_num=87) assert len(mag_ret) == 87 - @mplcleanup - def test_bode_feature_periphery_decade(self): + def test_bode_feature_periphery_decade(self, mplcleanup): # Generate a sample Bode plot to figure out the range it uses ct.reset_defaults() # Make sure starting state is correct mag_ret, phase_ret, omega_ret = ct.bode_plot(self.sys, Hz=False) diff --git a/control/tests/conftest.py b/control/tests/conftest.py index 1201b8746..3f798f26c 100644 --- a/control/tests/conftest.py +++ b/control/tests/conftest.py @@ -1,13 +1,11 @@ """conftest.py - pytest local plugins and fixtures""" import os -import sys from contextlib import contextmanager import matplotlib as mpl import numpy as np import pytest -import scipy as sp import control @@ -45,7 +43,7 @@ def control_defaults(): params=[pytest.param("arrayout", marks=matrixerrorfilter), pytest.param("matrixout", marks=matrixfilter)]) def matarrayout(request): - """Switch the config to use np.ndarray and np.matrix as returns""" + """Switch the config to use np.ndarray and np.matrix as returns.""" restore = control.config.defaults['statesp.use_numpy_matrix'] control.use_numpy_matrix(request.param == "matrixout", warn=False) yield @@ -53,7 +51,7 @@ def matarrayout(request): def ismatarrayout(obj): - """Test if the returned object has the correct type as configured + """Test if the returned object has the correct type as configured. note that isinstance(np.matrix(obj), np.ndarray) is True """ @@ -63,7 +61,7 @@ def ismatarrayout(obj): def asmatarrayout(obj): - """Return a object according to the configured default""" + """Return a object according to the configured default.""" use_matrix = control.config.defaults['statesp.use_numpy_matrix'] matarray = np.asmatrix if use_matrix else np.asarray return matarray(obj) @@ -71,7 +69,7 @@ def asmatarrayout(obj): @contextmanager def check_deprecated_matrix(): - """Check that a call produces a deprecation warning because of np.matrix""" + """Check that a call produces a deprecation warning because of np.matrix.""" use_matrix = control.config.defaults['statesp.use_numpy_matrix'] if use_matrix: with pytest.deprecated_call(): @@ -94,13 +92,13 @@ def check_deprecated_matrix(): False)] if usebydefault or TEST_MATRIX_AND_ARRAY]) def matarrayin(request): - """Use array and matrix to construct input data in tests""" + """Use array and matrix to construct input data in tests.""" return request.param @pytest.fixture(scope="function") def editsdefaults(): - """Make sure any changes to the defaults only last during a test""" + """Make sure any changes to the defaults only last during a test.""" restore = control.config.defaults.copy() yield control.config.defaults = restore.copy() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy