Hello community,
here is the log from the commit of package python-threadpoolctl for
openSUSE:Factory checked in at 2020-07-26 16:19:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-threadpoolctl (Old)
and /work/SRC/openSUSE:Factory/.python-threadpoolctl.new.3592 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-threadpoolctl"
Sun Jul 26 16:19:06 2020 rev:2 rq:822657 version:2.1.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-threadpoolctl/python-threadpoolctl.changes
2020-03-05 23:24:40.297389756 +0100
+++
/work/SRC/openSUSE:Factory/.python-threadpoolctl.new.3592/python-threadpoolctl.changes
2020-07-26 16:19:51.536837182 +0200
@@ -1,0 +2,10 @@
+Fri Jul 24 11:21:21 UTC 2020 - Marketa Calabkova <[email protected]>
+
+- update to 2.1.0
+ * New commandline interface: 'python -m threadpoolctl -i numpy'
+ will try to import the `numpy` package and then return the output of
+ `threadpoolctl.threadpool_info()` on STDOUT formatted using the JSON
+ syntax. This makes it easier to quickly introspect a Python environment.
+- Add patch python_executable.patch
+
+-------------------------------------------------------------------
Old:
----
threadpoolctl-2.0.0.tar.gz
New:
----
python_executable.patch
threadpoolctl-2.1.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-threadpoolctl.spec ++++++
--- /var/tmp/diff_new_pack.jwAFGA/_old 2020-07-26 16:19:52.056837668 +0200
+++ /var/tmp/diff_new_pack.jwAFGA/_new 2020-07-26 16:19:52.060837672 +0200
@@ -19,13 +19,15 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-threadpoolctl
-Version: 2.0.0
+Version: 2.1.0
Release: 0
Summary: Thread-pool Controls
License: BSD-3-Clause
Group: Development/Languages/Python
URL: https://github.com/joblib/threadpoolctl
Source:
https://files.pythonhosted.org/packages/source/t/threadpoolctl/threadpoolctl-%{version}.tar.gz
+# fix python executable in tests
+Patch0: python_executable.patch
BuildRequires: %{python_module devel}
BuildRequires: %{python_module pytest}
BuildRequires: %{python_module setuptools}
@@ -41,6 +43,7 @@
%prep
%setup -q -n threadpoolctl-%{version}
+%patch0 -p1
%build
%python_build
++++++ python_executable.patch ++++++
Index: threadpoolctl-2.1.0/tests/test_threadpoolctl.py
===================================================================
--- threadpoolctl-2.1.0.orig/tests/test_threadpoolctl.py
+++ threadpoolctl-2.1.0/tests/test_threadpoolctl.py
@@ -396,14 +396,14 @@ def test_libomp_libiomp_warning(recwarn)
def test_command_line_empty():
output = subprocess.check_output(
- "python -m threadpoolctl".split())
+ (sys.executable + " -m threadpoolctl").split())
assert json.loads(output.decode("utf-8")) == []
def test_command_line_command_flag():
pytest.importorskip("numpy")
output = subprocess.check_output(
- ["python", "-m", "threadpoolctl", "-c", "import numpy"])
+ [sys.executable, "-m", "threadpoolctl", "-c", "import numpy"])
cli_info = json.loads(output.decode("utf-8"))
this_process_info = threadpool_info()
@@ -415,7 +415,7 @@ def test_command_line_command_flag():
reason="need recent subprocess.run options")
def test_command_line_import_flag():
result = subprocess.run([
- "python", "-m", "threadpoolctl", "-i",
+ sys.executable, "-m", "threadpoolctl", "-i",
"numpy",
"scipy.linalg",
"invalid_package",
++++++ threadpoolctl-2.0.0.tar.gz -> threadpoolctl-2.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/threadpoolctl-2.0.0/CHANGES.md
new/threadpoolctl-2.1.0/CHANGES.md
--- old/threadpoolctl-2.0.0/CHANGES.md 2019-12-05 18:18:43.089723600 +0100
+++ new/threadpoolctl-2.1.0/CHANGES.md 2020-05-29 11:11:42.282364600 +0200
@@ -1,5 +1,17 @@
+2.1.0 (2020-05-29)
+==================
+
+- New commandline interface:
+
+ python -m threadpoolctl -i numpy
+
+ will try to import the `numpy` package and then return the output of
+ `threadpoolctl.threadpool_info()` on STDOUT formatted using the JSON
+ syntax. This makes it easier to quickly introspect a Python environment.
+
+
2.0.0 (2019-12-05)
-===========
+==================
- Expose MKL, BLIS and OpenBLAS threading layer in informations displayed by
`threadpool_info`. This information is referenced in the `threading_layer`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/threadpoolctl-2.0.0/PKG-INFO
new/threadpoolctl-2.1.0/PKG-INFO
--- old/threadpoolctl-2.0.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/threadpoolctl-2.1.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: threadpoolctl
-Version: 2.0.0
+Version: 2.1.0
Summary: threadpoolctl
Home-page: https://github.com/joblib/threadpoolctl
Author: Thomas Moreau
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/threadpoolctl-2.0.0/README.md
new/threadpoolctl-2.1.0/README.md
--- old/threadpoolctl-2.0.0/README.md 2019-11-15 17:14:06.539986000 +0100
+++ new/threadpoolctl-2.1.0/README.md 2020-05-25 11:10:49.357650500 +0200
@@ -32,7 +32,38 @@
## Usage
-### Runtime Introspection
+### Command Line Interface
+
+Get a JSON description of thread-pools initialized when importing python
+packages such as numpy or scipy for instance:
+
+```
+python -m threadpoolctl -i numpy scipy.linalg
+[
+ {
+ "filepath": "/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so",
+ "prefix": "libmkl_rt",
+ "user_api": "blas",
+ "internal_api": "mkl",
+ "version": "2019.0.4",
+ "num_threads": 2,
+ "threading_layer": "intel"
+ },
+ {
+ "filepath": "/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so",
+ "prefix": "libiomp",
+ "user_api": "openmp",
+ "internal_api": "openmp",
+ "version": null,
+ "num_threads": 4
+ }
+]
+```
+
+The JSON information is written on STDOUT. If some of the packages are missing,
+a warning message is displayed on STDERR.
+
+### Python Runtime Programmatic Introspection
Introspect the current state of the threadpool-enabled runtime libraries
that are loaded when importing Python packages:
@@ -45,28 +76,36 @@
>>> import numpy
>>> pprint(threadpool_info())
-[{'filepath':
'/opt/venvs/py37/lib/python3.7/site-packages/numpy/.libs/libopenblasp-r0-382c8f3a.3.5.dev.so',
- 'internal_api': 'openblas',
- 'num_threads': 4,
- 'prefix': 'libopenblas',
+[{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so',
+ 'internal_api': 'mkl',
+ 'num_threads': 2,
+ 'prefix': 'libmkl_rt',
+ 'threading_layer': 'intel',
'user_api': 'blas',
- 'version': '0.3.5.dev'}]
+ 'version': '2019.0.4'},
+ {'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so',
+ 'internal_api': 'openmp',
+ 'num_threads': 4,
+ 'prefix': 'libiomp',
+ 'user_api': 'openmp',
+ 'version': None}]
>>> import xgboost
>>> pprint(threadpool_info())
-[{'filepath':
'/opt/venvs/py37/lib/python3.7/site-packages/numpy/.libs/libopenblasp-r0-382c8f3a.3.5.dev.so',
- 'internal_api': 'openblas',
- 'num_threads': 4,
- 'prefix': 'libopenblas',
+[{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so',
+ 'internal_api': 'mkl',
+ 'num_threads': 2,
+ 'prefix': 'libmkl_rt',
+ 'threading_layer': 'intel',
'user_api': 'blas',
- 'version': '0.3.5.dev'},
- {'filepath':
'/opt/venvs/py37/lib/python3.7/site-packages/scipy/.libs/libopenblasp-r0-8dca6697.3.0.dev.so',
- 'internal_api': 'openblas',
+ 'version': '2019.0.4'},
+ {'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so',
+ 'internal_api': 'openmp',
'num_threads': 4,
- 'prefix': 'libopenblas',
- 'user_api': 'blas',
+ 'prefix': 'libiomp',
+ 'user_api': 'openmp',
'version': None},
- {'filepath': '/usr/lib/x86_64-linux-gnu/libgomp.so.1',
+ {'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libgomp.so.1.0.0',
'internal_api': 'openmp',
'num_threads': 4,
'prefix': 'libgomp',
@@ -74,7 +113,12 @@
'version': None}]
```
-### Set the maximum size of thread-pools
+In the above example, `numpy` was installed from the default anaconda channel
and
+comes with the MKL and its Intel OpenMP (`libiomp5`) implementation while
+`xgboost` was installed from pypi.org and links against GNU OpenMP (`libgomp`)
+so both OpenMP runtimes are loaded in the same Python program.
+
+### Setting the Maximum Size of Thread-Pools
Control the number of threads used by the underlying runtime libraries
in specific sections of your Python program:
@@ -92,14 +136,28 @@
a_squared = a @ a
```
-### Known limitation
+### Known Limitations
-`threadpool_limits` does not act as expected in nested parallel loops
-managed by distinct OpenMP runtime implementations (for instance libgomp
-from GCC and libomp from clang/llvm or libiomp from ICC).
+- `threadpool_limits` can fail to limit the number of inner threads when
nesting
+ parallel loops managed by distinct OpenMP runtime implementations (for
instance
+ libgomp from GCC and libomp from clang/llvm or libiomp from ICC).
+
+ See the `test_openmp_nesting` function in [tests/test_threadpoolctl.py](
+
https://github.com/joblib/threadpoolctl/blob/master/tests/test_threadpoolctl.py)
+ for an example. More information can be found at:
+ https://github.com/jeremiedbb/Nested_OpenMP
+
+ Note however that this problem does not happen when `threadpool_limits` is
+ used to limit the number of threads used internally by BLAS calls that are
+ themselves nested under OpenMP parallel loops. `threadpool_limits` works as
+ expected, even if the inner BLAS implementation relies on a distinct OpenMP
+ implementation.
+
+- Using Intel OpenMP (ICC) and LLVM OpenMP (clang) in the same Python program
+ under Linux is known to cause problems. See the following guide for more
details
+ and workarounds:
+ https://github.com/joblib/threadpoolctl/blob/master/multiple_openmp.md
-See the `test_openmp_nesting()` function in `tests/test_threadpoolctl.py`
-for an example.
## Maintainers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/threadpoolctl-2.0.0/continuous_integration/display_versions.py
new/threadpoolctl-2.1.0/continuous_integration/display_versions.py
--- old/threadpoolctl-2.0.0/continuous_integration/display_versions.py
2019-06-05 15:55:01.186587600 +0200
+++ new/threadpoolctl-2.1.0/continuous_integration/display_versions.py
1970-01-01 01:00:00.000000000 +0100
@@ -1,23 +0,0 @@
-from threadpoolctl import threadpool_info
-from pprint import pprint
-
-try:
- import numpy as np
- print("numpy", np.__version__)
-except ImportError:
- pass
-
-try:
- import scipy
- import scipy.linalg
- print("scipy", scipy.__version__)
-except ImportError:
- pass
-
-try:
- from tests._openmp_test_helper import * # noqa
-except ImportError:
- pass
-
-
-pprint(threadpool_info())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/threadpoolctl-2.0.0/continuous_integration/test_script.cmd
new/threadpoolctl-2.1.0/continuous_integration/test_script.cmd
--- old/threadpoolctl-2.0.0/continuous_integration/test_script.cmd
2019-12-05 18:07:10.028120500 +0100
+++ new/threadpoolctl-2.1.0/continuous_integration/test_script.cmd
2020-05-25 11:10:49.357650500 +0200
@@ -1,5 +1,7 @@
call activate %VIRTUALENV%
-python continuous_integration/display_versions.py
+# Use the CLI to display the effective runtime environment prior to
+# launching the tests:
+python -m threadpoolctl -i numpy scipy.linalg tests._openmp_test_helper
pytest -vlrxXs --junitxml=%JUNITXML% --cov=threadpoolctl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/threadpoolctl-2.0.0/continuous_integration/test_script.sh
new/threadpoolctl-2.1.0/continuous_integration/test_script.sh
--- old/threadpoolctl-2.0.0/continuous_integration/test_script.sh
2019-12-05 18:07:10.028120500 +0100
+++ new/threadpoolctl-2.1.0/continuous_integration/test_script.sh
2020-05-25 11:10:49.357650500 +0200
@@ -12,6 +12,9 @@
fi
set -x
-PYTHONPATH="." python continuous_integration/display_versions.py
+
+# Use the CLI to display the effective runtime environment prior to
+# launching the tests:
+python -m threadpoolctl -i numpy scipy.linalg tests._openmp_test_helper
pytest -vlrxXs -W error -k "$TESTS" --junitxml=$JUNITXML --cov=threadpoolctl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/threadpoolctl-2.0.0/multiple_openmp.md
new/threadpoolctl-2.1.0/multiple_openmp.md
--- old/threadpoolctl-2.0.0/multiple_openmp.md 2019-12-05 18:07:10.028120500
+0100
+++ new/threadpoolctl-2.1.0/multiple_openmp.md 2020-01-13 13:35:43.897076800
+0100
@@ -1,53 +1,85 @@
-# Multiple OpenMP runtimes
+# Multiple OpenMP Runtimes
+
+## Context
OpenMP is an API specification for parallel programming. There are many
-implementations of it, tied to a compiler most of the time: the libgomp library
-for GCC, libomp for LLVM/Clang, libiomp for ICC and vcomp for MSVC for example.
-In the following, we refer to OpenMP without distinction between the
-specification and an implementation.
-
-In general, it's not advised to have different OpenMP libraries (or even
-different copies of the same library) loaded at the same time in a program.
-It's considered an undefined behavior. Fortunately it's not as bad as it sounds
-in most situations.
-
-However it can easily happen in the Python ecosystem since you can install
-packages compiled with different compilers (hence linked to different OpenMP
-implementations) and import them in a same Python program.
-
-A typical example is installing numpy from Anaconda which ships MKL
-(Intel's math library) and a package using multi-threading with OpenMP
-(Scikit-learn, LightGBM, XGBoost, ...).
-
-From our experience, most OpenMP libraries can seamlessly coexist in a same
-program. For instance, on Linux, we never observed any issue between libgomp
-and libiomp, which is the most common mix (numpy with MKL + a package compiled
-with GCC, the most widely used C compiler).
-
-The only unrecoverable incompatibility we encountered is between libomp
-(LLVM/Clang) and libiomp (ICC), on Linux, manifested by crashes or deadlocks.
-It can happen even with the simplest OpenMP calls like getting the maximum
-number of threads that will be used in a subsequent parallel region. A possible
-explanation is that libomp is actually a fork of libiomp causing name colliding
-for instance. Using threadpoolctl may crash your program in such a setting.
+implementations of it, tied to a compiler most of the time:
+
+- `libgomp` for GCC (GNU C/C++ Compiler),
+- `libomp` for Clang (LLVM C/C++ Compiler),
+- `libiomp` for ICC (Intel C/C++ Compiler),
+- `vcomp` for MSVC (Microsoft Visual Studio C/C++ Compiler).
+
+In general, it is not advised to have different OpenMP runtime libraries (or
+even different copies of the same library) loaded at the same time in a
+program. It's considered an undefined behavior. Fortunately it is not as bad as
+it sounds in most situations.
+
+However this situation is frequent in the Python ecosystem since you can
+install packages compiled with different compilers (hence linked to different
+OpenMP implementations) and import them together in a Python program.
+
+A typical example is installing NumPy from Anaconda which is linked against MKL
+(Intel's math library) and another package that uses multi-threading with
OpenMP
+directly in a compiled extension, as is the case in Scikit-learn (via Cython
+`prange`), LightGBM and XGBoost (via pragmas in the C++ source code).
+
+From our experience, **most OpenMP libraries can seamlessly coexist in a same
+program**. For instance, on Linux, we never observed any issue between
+`libgomp` and `libiomp`, which is the most common mix (NumPy with MKL + a
+package compiled with GCC, the most widely used C compiler on that platform).
+
+## Incompatibility between Intel OpenMP and LLVM OpenMP under Linux
+
+The only unrecoverable incompatibility we encountered happens when loading a
+mix of compiled extensions linked with **`libomp` (LLVM/Clang) and `libiomp`
+(ICC), on Linux**, manifested by crashes or deadlocks. It can happen even with
+the simplest OpenMP calls like getting the maximum number of threads that will
+be used in a subsequent parallel region. A possible explanation is that
+`libomp` is actually a fork of `libiomp` causing name colliding for instance.
+Using `threadpoolctl` may crash your program in such a setting.
+
+**Fortunately this problem is very rare**: at the time of writing, all major
+binary distributions of Python packages for Linux use either GCC or ICC to
+build the Python scientific packages. Therefore this problem would only happen
+if some packagers decide to start shipping Python packages built with
+LLVM/Clang instead of GCC.
Surprisingly, we never encountered this kind of issue on macOS, where this mix
is the most frequent (Clang being the default C compiler on macOS).
-As far as we know, the only workaround consists in getting rid of one of the
-OpenMP libraries. For example:
+## Workarounds for Intel OpenMP and LLVM OpenMP case
+
+As far as we know, the only workaround consists in making sure only of one of
+the two incompatible OpenMP libraries is loaded. For example:
+
+- Tell MKL (used by NumPy) to use the GNU OpenMP runtime instead of the Intel
+ OpenMP runtime by setting the following environment variable:
+
+ export MKL_THREADING_LAYER=GNU
+
+- Install a build of NumPy and SciPy linked against OpenBLAS instead of MKL.
+ This can be done for instance by installing NumPy and SciPy from PyPI:
+
+ pip install numpy scipy
+
+ from the conda-forge conda channel:
-- Build your OpenMP-enabled extensions with GCC (or ICC) instead of Clang.
+ conda install -c conda-forge numpy scipy
-- Install a build of Numpy linked against OpenBLAS instead of MKL. This can be
- done for instance by installing Numpy from PyPI::
+ or from the default conda channel:
- pip install numpy
+ conda install numpy scipy blas[build=openblas]
- from the conda-forge conda channel::
+- Re-build your OpenMP-enabled extensions from source with GCC (or ICC) instead
+ of Clang if you want to keep on using NumPy/SciPy linked against MKL with the
+ default `libiomp`-based threading layer.
- conda install -c conda-forge numpy
+## References
- or from the default conda channel::
+The above incompatibility has been reported upstream to the LLVM and Intel
+developers on the following public issue trackers/forums along with a minimal
+reproducer written in C:
- conda install numpy blas[build=openblas]
+- https://bugs.llvm.org/show_bug.cgi?id=43565
+- https://software.intel.com/en-us/forums/intel-c-compiler/topic/827607
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/threadpoolctl-2.0.0/setup.py
new/threadpoolctl-2.1.0/setup.py
--- old/threadpoolctl-2.0.0/setup.py 1970-01-01 01:00:00.000000000 +0100
+++ new/threadpoolctl-2.1.0/setup.py 1970-01-01 01:00:00.000000000 +0100
@@ -5,7 +5,7 @@
setup(name='threadpoolctl',
- version='2.0.0',
+ version='2.1.0',
description='threadpoolctl',
author='Thomas Moreau',
author_email='[email protected]',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/threadpoolctl-2.0.0/tests/_openmp_test_helper/__init__.py
new/threadpoolctl-2.1.0/tests/_openmp_test_helper/__init__.py
--- old/threadpoolctl-2.0.0/tests/_openmp_test_helper/__init__.py
2019-09-25 10:35:31.332812000 +0200
+++ new/threadpoolctl-2.1.0/tests/_openmp_test_helper/__init__.py
2020-05-25 11:10:49.357650500 +0200
@@ -2,7 +2,12 @@
from .openmp_helpers_inner import get_compiler as get_inner_compiler
from .openmp_helpers_outer import check_nested_openmp_loops
from .openmp_helpers_outer import get_compiler as get_outer_compiler
-from .nested_prange_blas import check_nested_prange_blas
+
+try:
+ from .nested_prange_blas import check_nested_prange_blas
+except ImportError:
+ # Can happen if numpy and scipy are missing.
+ check_nested_prange_blas = None
__all__ = ["check_openmp_num_threads",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/threadpoolctl-2.0.0/tests/test_threadpoolctl.py
new/threadpoolctl-2.1.0/tests/test_threadpoolctl.py
--- old/threadpoolctl-2.0.0/tests/test_threadpoolctl.py 2019-12-05
18:07:10.028120500 +0100
+++ new/threadpoolctl-2.1.0/tests/test_threadpoolctl.py 2020-05-25
11:10:49.357650500 +0200
@@ -1,7 +1,9 @@
+import json
import os
+import pytest
import re
+import subprocess
import sys
-import pytest
from threadpoolctl import threadpool_limits, threadpool_info, _ThreadpoolInfo
from threadpoolctl import _ALL_PREFIXES, _ALL_USER_APIS
@@ -261,6 +263,8 @@
@pytest.mark.skipif(scipy is None, reason="requires scipy")
[email protected](not cython_extensions_compiled,
+ reason='Requires cython extensions to be compiled')
@pytest.mark.parametrize("nthreads_outer", [None, 1, 2, 4])
def test_nested_prange_blas(nthreads_outer):
# Check that the BLAS linked to scipy effectively uses the number of
@@ -371,7 +375,7 @@
from ._openmp_test_helper import check_nested_openmp_loops # noqa
# Trigger the import of numpy to potentially import Intel OpenMP via MKL
- import numpy.linalg # noqa
+ pytest.importorskip("numpy.linalg")
# Check that a warning is raised when both libomp and libiomp are loaded
# It should happen in one CI job (pylatest_conda_mkl_clang_gcc).
@@ -388,3 +392,45 @@
assert "Found Intel" in str(wm.message)
assert "LLVM" in str(wm.message)
assert "multiple_openmp.md" in str(wm.message)
+
+
+def test_command_line_empty():
+ output = subprocess.check_output(
+ "python -m threadpoolctl".split())
+ assert json.loads(output.decode("utf-8")) == []
+
+
+def test_command_line_command_flag():
+ pytest.importorskip("numpy")
+ output = subprocess.check_output(
+ ["python", "-m", "threadpoolctl", "-c", "import numpy"])
+ cli_info = json.loads(output.decode("utf-8"))
+
+ this_process_info = threadpool_info()
+ for module in cli_info:
+ assert module in this_process_info
+
+
[email protected](sys.version_info < (3, 7),
+ reason="need recent subprocess.run options")
+def test_command_line_import_flag():
+ result = subprocess.run([
+ "python", "-m", "threadpoolctl", "-i",
+ "numpy",
+ "scipy.linalg",
+ "invalid_package",
+ "numpy.invalid_sumodule",
+ ], capture_output=True, check=True, encoding="utf-8")
+ cli_info = json.loads(result.stdout)
+
+ this_process_info = threadpool_info()
+ for module in cli_info:
+ assert module in this_process_info
+
+ warnings = [w.strip() for w in result.stderr.splitlines()]
+ assert "WARNING: could not import invalid_package" in warnings
+ assert "WARNING: could not import numpy.invalid_sumodule" in warnings
+ if scipy is None:
+ assert "WARNING: could not import scipy.linalg" in warnings
+ else:
+ assert "WARNING: could not import scipy.linalg" not in warnings
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/threadpoolctl-2.0.0/threadpoolctl.py
new/threadpoolctl-2.1.0/threadpoolctl.py
--- old/threadpoolctl-2.0.0/threadpoolctl.py 2019-12-05 18:18:04.565399200
+0100
+++ new/threadpoolctl-2.1.0/threadpoolctl.py 2020-05-29 11:13:31.525606200
+0200
@@ -19,7 +19,7 @@
from ctypes.util import find_library
from abc import ABC, abstractmethod
-__version__ = "2.0.0"
+__version__ = "2.1.0"
__all__ = ["threadpool_limits", "threadpool_info"]
@@ -757,3 +757,40 @@
def _get_extra_info(self):
pass
+
+
+def _main():
+ """Commandline interface to display thread-pool information and exit."""
+ import argparse
+ import importlib
+ import json
+ import sys
+
+ parser = argparse.ArgumentParser(
+ usage="python -m threadpoolctl -i numpy scipy.linalg xgboost",
+ description="Display thread-pool information and exit.",
+ )
+ parser.add_argument(
+ "-i", "--import", dest="modules", nargs="*", default=(),
+ help="Python modules to import before introspecting thread-pools."
+ )
+ parser.add_argument(
+ "-c", "--command",
+ help="a Python statement to execute before introspecting"
+ " thread-pools.")
+
+ options = parser.parse_args(sys.argv[1:])
+ for module in options.modules:
+ try:
+ importlib.import_module(module, package=None)
+ except ImportError:
+ print("WARNING: could not import", module, file=sys.stderr)
+
+ if options.command:
+ exec(options.command)
+
+ print(json.dumps(threadpool_info(), indent=2))
+
+
+if __name__ == "__main__":
+ _main()