Compare commits
10 Commits
c97a4ca0b6
...
9cccb00151
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cccb00151 | ||
|
|
aabcb18c7e | ||
|
|
19e1da2395 | ||
|
|
c069ae099b | ||
|
|
baa36552fb | ||
|
|
a26854a04f | ||
|
|
6a95043386 | ||
|
|
4f86cc0d52 | ||
|
|
5e0c3b2ea9 | ||
|
|
32e4116844 |
147
0001-Backport-thread_name_prefix-from-upstream-64.patch
Normal file
147
0001-Backport-thread_name_prefix-from-upstream-64.patch
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
From e8543e620d87f41f78751b4285a3f1af06023a62 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Steven Seguin <sseg@users.noreply.github.com>
|
||||||
|
Date: Tue, 8 Aug 2017 11:34:27 -0400
|
||||||
|
Subject: [PATCH] Backport `thread_name_prefix` from upstream (#64)
|
||||||
|
|
||||||
|
Changes from https://github.com/python/cpython/pull/2315
|
||||||
|
|
||||||
|
Fixes #63.
|
||||||
|
---
|
||||||
|
CHANGES | 7 +++++++
|
||||||
|
concurrent/futures/thread.py | 17 ++++++++++++++---
|
||||||
|
test_futures.py | 29 ++++++++++++++++++++++++++---
|
||||||
|
3 files changed, 47 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/CHANGES b/CHANGES
|
||||||
|
index 4ce2585..f7d411c 100644
|
||||||
|
--- a/CHANGES
|
||||||
|
+++ b/CHANGES
|
||||||
|
@@ -1,3 +1,10 @@
|
||||||
|
+Unreleased
|
||||||
|
+==========
|
||||||
|
+
|
||||||
|
+- The ThreadPoolExecutor class constructor now accepts an optional ``thread_name_prefix``
|
||||||
|
+ argument to make it possible to customize the names of the threads created by the pool.
|
||||||
|
+ Upstream contribution by Gregory P. Smith in https://bugs.python.org/issue27664.
|
||||||
|
+
|
||||||
|
3.1.1
|
||||||
|
=====
|
||||||
|
|
||||||
|
diff --git a/concurrent/futures/thread.py b/concurrent/futures/thread.py
|
||||||
|
index efae619..bb0ce9d 100644
|
||||||
|
--- a/concurrent/futures/thread.py
|
||||||
|
+++ b/concurrent/futures/thread.py
|
||||||
|
@@ -5,6 +5,7 @@
|
||||||
|
|
||||||
|
import atexit
|
||||||
|
from concurrent.futures import _base
|
||||||
|
+import itertools
|
||||||
|
import Queue as queue
|
||||||
|
import threading
|
||||||
|
import weakref
|
||||||
|
@@ -90,12 +91,17 @@ def _worker(executor_reference, work_queue):
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadPoolExecutor(_base.Executor):
|
||||||
|
- def __init__(self, max_workers=None):
|
||||||
|
+
|
||||||
|
+ # Used to assign unique thread names when thread_name_prefix is not supplied.
|
||||||
|
+ _counter = itertools.count().next
|
||||||
|
+
|
||||||
|
+ def __init__(self, max_workers=None, thread_name_prefix=''):
|
||||||
|
"""Initializes a new ThreadPoolExecutor instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
max_workers: The maximum number of threads that can be used to
|
||||||
|
execute the given calls.
|
||||||
|
+ thread_name_prefix: An optional name prefix to give our threads.
|
||||||
|
"""
|
||||||
|
if max_workers is None:
|
||||||
|
# Use this number because ThreadPoolExecutor is often
|
||||||
|
@@ -109,6 +115,8 @@ class ThreadPoolExecutor(_base.Executor):
|
||||||
|
self._threads = set()
|
||||||
|
self._shutdown = False
|
||||||
|
self._shutdown_lock = threading.Lock()
|
||||||
|
+ self._thread_name_prefix = (thread_name_prefix or
|
||||||
|
+ ("ThreadPoolExecutor-%d" % self._counter()))
|
||||||
|
|
||||||
|
def submit(self, fn, *args, **kwargs):
|
||||||
|
with self._shutdown_lock:
|
||||||
|
@@ -130,8 +138,11 @@ class ThreadPoolExecutor(_base.Executor):
|
||||||
|
q.put(None)
|
||||||
|
# TODO(bquinlan): Should avoid creating new threads if there are more
|
||||||
|
# idle threads than items in the work queue.
|
||||||
|
- if len(self._threads) < self._max_workers:
|
||||||
|
- t = threading.Thread(target=_worker,
|
||||||
|
+ num_threads = len(self._threads)
|
||||||
|
+ if num_threads < self._max_workers:
|
||||||
|
+ thread_name = '%s_%d' % (self._thread_name_prefix or self,
|
||||||
|
+ num_threads)
|
||||||
|
+ t = threading.Thread(name=thread_name, target=_worker,
|
||||||
|
args=(weakref.ref(self, weakref_cb),
|
||||||
|
self._work_queue))
|
||||||
|
t.daemon = True
|
||||||
|
diff --git a/test_futures.py b/test_futures.py
|
||||||
|
index e7cd8cf..95a3ca2 100644
|
||||||
|
--- a/test_futures.py
|
||||||
|
+++ b/test_futures.py
|
||||||
|
@@ -29,7 +29,7 @@ def reap_threads(func):
|
||||||
|
If threading is unavailable this function does nothing.
|
||||||
|
"""
|
||||||
|
@functools.wraps(func)
|
||||||
|
- def decorator(*args):
|
||||||
|
+ def decorator(*args):
|
||||||
|
key = test_support.threading_setup()
|
||||||
|
try:
|
||||||
|
return func(*args)
|
||||||
|
@@ -50,7 +50,7 @@ def _assert_python(expected_success, *args, **env_vars):
|
||||||
|
# caller is responsible to pass the full environment.
|
||||||
|
if env_vars.pop('__cleanenv', None):
|
||||||
|
env = {}
|
||||||
|
- env.update(env_vars)
|
||||||
|
+ env.update(env_vars)
|
||||||
|
cmd_line.extend(args)
|
||||||
|
p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
|
@@ -78,7 +78,7 @@ def assert_python_ok(*args, **env_vars):
|
||||||
|
return _assert_python(True, *args, **env_vars)
|
||||||
|
|
||||||
|
|
||||||
|
-def strip_python_stderr(stderr):
|
||||||
|
+def strip_python_stderr(stderr):
|
||||||
|
"""Strip the stderr of a Python process from potential debug output
|
||||||
|
emitted by the interpreter.
|
||||||
|
|
||||||
|
@@ -230,6 +230,29 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest):
|
||||||
|
for t in threads:
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
+ def test_thread_names_assigned(self):
|
||||||
|
+ executor = futures.ThreadPoolExecutor(
|
||||||
|
+ max_workers=5, thread_name_prefix='SpecialPool')
|
||||||
|
+ executor.map(abs, range(-5, 5))
|
||||||
|
+ threads = executor._threads
|
||||||
|
+ del executor
|
||||||
|
+
|
||||||
|
+ for t in threads:
|
||||||
|
+ self.assertRegexpMatches(t.name, r'^SpecialPool_[0-4]$')
|
||||||
|
+ t.join()
|
||||||
|
+
|
||||||
|
+ def test_thread_names_default(self):
|
||||||
|
+ executor = futures.ThreadPoolExecutor(max_workers=5)
|
||||||
|
+ executor.map(abs, range(-5, 5))
|
||||||
|
+ threads = executor._threads
|
||||||
|
+ del executor
|
||||||
|
+
|
||||||
|
+ for t in threads:
|
||||||
|
+ # Ensure that our default name is reasonably sane and unique when
|
||||||
|
+ # no thread_name_prefix was supplied.
|
||||||
|
+ self.assertRegexpMatches(t.name, r'ThreadPoolExecutor-\d+_[0-4]$')
|
||||||
|
+ t.join()
|
||||||
|
+
|
||||||
|
|
||||||
|
class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest):
|
||||||
|
def _prime_executor(self):
|
||||||
|
--
|
||||||
|
2.39.0.windows.2
|
||||||
|
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
From d0393ad626d25622927bb0ed47d35ddb2f6cd321 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eli Schwartz <eschwartz93@gmail.com>
|
||||||
|
Date: Fri, 27 Oct 2017 18:07:12 -0400
|
||||||
|
Subject: [PATCH] Specify python_requires to prevent installation on Python 3
|
||||||
|
(#67)
|
||||||
|
|
||||||
|
---
|
||||||
|
setup.py | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/setup.py b/setup.py
|
||||||
|
index ea0c022..eb43091 100755
|
||||||
|
--- a/setup.py
|
||||||
|
+++ b/setup.py
|
||||||
|
@@ -23,6 +23,7 @@ setup(name='futures',
|
||||||
|
maintainer_email='alex.gronholm+pypi@nextday.fi',
|
||||||
|
url='https://github.com/agronholm/pythonfutures',
|
||||||
|
packages=['concurrent', 'concurrent.futures'],
|
||||||
|
+ python_requires='>=2.6, <3',
|
||||||
|
license='PSF',
|
||||||
|
classifiers=['License :: OSI Approved :: Python Software Foundation License',
|
||||||
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
--
|
||||||
|
2.39.0.windows.2
|
||||||
|
|
||||||
121
0003-Backport-fixes-to-as_completed-and-map-iterators-bpo.patch
Normal file
121
0003-Backport-fixes-to-as_completed-and-map-iterators-bpo.patch
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
From 28fa404639a702c32a18a1a411409f1aab8ab464 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lisandro Dalcin <dalcinl@gmail.com>
|
||||||
|
Date: Wed, 29 Nov 2017 22:40:47 +0300
|
||||||
|
Subject: [PATCH] Backport fixes to as_completed and map iterators (bpo-27144)
|
||||||
|
(#66)
|
||||||
|
|
||||||
|
Python issues:
|
||||||
|
|
||||||
|
+ python/cpython#1560
|
||||||
|
+ python/cpython#3270
|
||||||
|
+ python/cpython#3830
|
||||||
|
---
|
||||||
|
concurrent/futures/_base.py | 53 ++++++++++++++++++++++++++++++-------
|
||||||
|
1 file changed, 43 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/concurrent/futures/_base.py b/concurrent/futures/_base.py
|
||||||
|
index 401e488..510ffa5 100644
|
||||||
|
--- a/concurrent/futures/_base.py
|
||||||
|
+++ b/concurrent/futures/_base.py
|
||||||
|
@@ -172,6 +172,29 @@ def _create_and_install_waiters(fs, return_when):
|
||||||
|
|
||||||
|
return waiter
|
||||||
|
|
||||||
|
+
|
||||||
|
+def _yield_finished_futures(fs, waiter, ref_collect):
|
||||||
|
+ """
|
||||||
|
+ Iterate on the list *fs*, yielding finished futures one by one in
|
||||||
|
+ reverse order.
|
||||||
|
+ Before yielding a future, *waiter* is removed from its waiters
|
||||||
|
+ and the future is removed from each set in the collection of sets
|
||||||
|
+ *ref_collect*.
|
||||||
|
+
|
||||||
|
+ The aim of this function is to avoid keeping stale references after
|
||||||
|
+ the future is yielded and before the iterator resumes.
|
||||||
|
+ """
|
||||||
|
+ while fs:
|
||||||
|
+ f = fs[-1]
|
||||||
|
+ for futures_set in ref_collect:
|
||||||
|
+ futures_set.remove(f)
|
||||||
|
+ with f._condition:
|
||||||
|
+ f._waiters.remove(waiter)
|
||||||
|
+ del f
|
||||||
|
+ # Careful not to keep a reference to the popped value
|
||||||
|
+ yield fs.pop()
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def as_completed(fs, timeout=None):
|
||||||
|
"""An iterator over the given futures that yields each as it completes.
|
||||||
|
|
||||||
|
@@ -194,16 +217,19 @@ def as_completed(fs, timeout=None):
|
||||||
|
end_time = timeout + time.time()
|
||||||
|
|
||||||
|
fs = set(fs)
|
||||||
|
+ total_futures = len(fs)
|
||||||
|
with _AcquireFutures(fs):
|
||||||
|
finished = set(
|
||||||
|
f for f in fs
|
||||||
|
if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
|
||||||
|
pending = fs - finished
|
||||||
|
waiter = _create_and_install_waiters(fs, _AS_COMPLETED)
|
||||||
|
-
|
||||||
|
+ finished = list(finished)
|
||||||
|
try:
|
||||||
|
- for future in finished:
|
||||||
|
- yield future
|
||||||
|
+ for f in _yield_finished_futures(finished, waiter,
|
||||||
|
+ ref_collect=(fs,)):
|
||||||
|
+ f = [f]
|
||||||
|
+ yield f.pop()
|
||||||
|
|
||||||
|
while pending:
|
||||||
|
if timeout is None:
|
||||||
|
@@ -213,7 +239,7 @@ def as_completed(fs, timeout=None):
|
||||||
|
if wait_timeout < 0:
|
||||||
|
raise TimeoutError(
|
||||||
|
'%d (of %d) futures unfinished' % (
|
||||||
|
- len(pending), len(fs)))
|
||||||
|
+ len(pending), total_futures))
|
||||||
|
|
||||||
|
waiter.event.wait(wait_timeout)
|
||||||
|
|
||||||
|
@@ -222,11 +248,15 @@ def as_completed(fs, timeout=None):
|
||||||
|
waiter.finished_futures = []
|
||||||
|
waiter.event.clear()
|
||||||
|
|
||||||
|
- for future in finished:
|
||||||
|
- yield future
|
||||||
|
- pending.remove(future)
|
||||||
|
+ # reverse to keep finishing order
|
||||||
|
+ finished.reverse()
|
||||||
|
+ for f in _yield_finished_futures(finished, waiter,
|
||||||
|
+ ref_collect=(fs, pending)):
|
||||||
|
+ f = [f]
|
||||||
|
+ yield f.pop()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
+ # Remove waiter from unfinished futures
|
||||||
|
for f in fs:
|
||||||
|
with f._condition:
|
||||||
|
f._waiters.remove(waiter)
|
||||||
|
@@ -603,11 +633,14 @@ class Executor(object):
|
||||||
|
# before the first iterator value is required.
|
||||||
|
def result_iterator():
|
||||||
|
try:
|
||||||
|
- for future in fs:
|
||||||
|
+ # reverse to keep finishing order
|
||||||
|
+ fs.reverse()
|
||||||
|
+ while fs:
|
||||||
|
+ # Careful not to keep a reference to the popped future
|
||||||
|
if timeout is None:
|
||||||
|
- yield future.result()
|
||||||
|
+ yield fs.pop().result()
|
||||||
|
else:
|
||||||
|
- yield future.result(end_time - time.time())
|
||||||
|
+ yield fs.pop().result(end_time - time.time())
|
||||||
|
finally:
|
||||||
|
for future in fs:
|
||||||
|
future.cancel()
|
||||||
|
--
|
||||||
|
2.39.0.windows.2
|
||||||
|
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
From 765e7e17975477b4e2fa60256007c970057e018d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lisandro Dalcin <dalcinl@gmail.com>
|
||||||
|
Date: Tue, 3 Oct 2017 21:35:10 +0300
|
||||||
|
Subject: [PATCH] Make Future.__repr__ subclass-friendly (bpo-22033) (#65)
|
||||||
|
|
||||||
|
+ https://bugs.python.org/issue22033
|
||||||
|
|
||||||
|
Minor spelling fixes in docstrings (bpo-25523)
|
||||||
|
|
||||||
|
+ https://bugs.python.org/issue25523
|
||||||
|
---
|
||||||
|
concurrent/futures/_base.py | 19 +++++++++++--------
|
||||||
|
1 file changed, 11 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/concurrent/futures/_base.py b/concurrent/futures/_base.py
|
||||||
|
index ca2ebfb..401e488 100644
|
||||||
|
--- a/concurrent/futures/_base.py
|
||||||
|
+++ b/concurrent/futures/_base.py
|
||||||
|
@@ -322,17 +322,20 @@ class Future(object):
|
||||||
|
with self._condition:
|
||||||
|
if self._state == FINISHED:
|
||||||
|
if self._exception:
|
||||||
|
- return '<Future at %s state=%s raised %s>' % (
|
||||||
|
- hex(id(self)),
|
||||||
|
+ return '<%s at %#x state=%s raised %s>' % (
|
||||||
|
+ self.__class__.__name__,
|
||||||
|
+ id(self),
|
||||||
|
_STATE_TO_DESCRIPTION_MAP[self._state],
|
||||||
|
self._exception.__class__.__name__)
|
||||||
|
else:
|
||||||
|
- return '<Future at %s state=%s returned %s>' % (
|
||||||
|
- hex(id(self)),
|
||||||
|
+ return '<%s at %#x state=%s returned %s>' % (
|
||||||
|
+ self.__class__.__name__,
|
||||||
|
+ id(self),
|
||||||
|
_STATE_TO_DESCRIPTION_MAP[self._state],
|
||||||
|
self._result.__class__.__name__)
|
||||||
|
- return '<Future at %s state=%s>' % (
|
||||||
|
- hex(id(self)),
|
||||||
|
+ return '<%s at %#x state=%s>' % (
|
||||||
|
+ self.__class__.__name__,
|
||||||
|
+ id(self),
|
||||||
|
_STATE_TO_DESCRIPTION_MAP[self._state])
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
@@ -355,7 +358,7 @@ class Future(object):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def cancelled(self):
|
||||||
|
- """Return True if the future has cancelled."""
|
||||||
|
+ """Return True if the future was cancelled."""
|
||||||
|
with self._condition:
|
||||||
|
return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]
|
||||||
|
|
||||||
|
@@ -573,7 +576,7 @@ class Executor(object):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def map(self, fn, *iterables, **kwargs):
|
||||||
|
- """Returns a iterator equivalent to map(fn, iter).
|
||||||
|
+ """Returns an iterator equivalent to map(fn, iter).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fn: A callable that will take as many arguments as there are
|
||||||
|
--
|
||||||
|
2.39.0.windows.2
|
||||||
|
|
||||||
32
0005-Fixed-tests-hanging-on-PyPy.patch
Normal file
32
0005-Fixed-tests-hanging-on-PyPy.patch
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
From 718654e8142d229655d7322dbc2ede8855270e58 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= <alex.gronholm@nextday.fi>
|
||||||
|
Date: Wed, 29 Nov 2017 23:06:58 +0200
|
||||||
|
Subject: [PATCH] Fixed tests hanging on PyPy
|
||||||
|
|
||||||
|
---
|
||||||
|
test_futures.py | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/test_futures.py b/test_futures.py
|
||||||
|
index 95a3ca2..d5b3499 100644
|
||||||
|
--- a/test_futures.py
|
||||||
|
+++ b/test_futures.py
|
||||||
|
@@ -236,6 +236,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest):
|
||||||
|
executor.map(abs, range(-5, 5))
|
||||||
|
threads = executor._threads
|
||||||
|
del executor
|
||||||
|
+ gc.collect()
|
||||||
|
|
||||||
|
for t in threads:
|
||||||
|
self.assertRegexpMatches(t.name, r'^SpecialPool_[0-4]$')
|
||||||
|
@@ -246,6 +247,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest):
|
||||||
|
executor.map(abs, range(-5, 5))
|
||||||
|
threads = executor._threads
|
||||||
|
del executor
|
||||||
|
+ gc.collect()
|
||||||
|
|
||||||
|
for t in threads:
|
||||||
|
# Ensure that our default name is reasonably sane and unique when
|
||||||
|
--
|
||||||
|
2.39.0.windows.2
|
||||||
|
|
||||||
@ -1,10 +1,15 @@
|
|||||||
Name: python-futures
|
Name: python-futures
|
||||||
Version: 3.1.1
|
Version: 3.1.1
|
||||||
Release: 5
|
Release: 10
|
||||||
Summary: Backport of the concurrent.futures standard library module to Python 3.2
|
Summary: Backport of the concurrent.futures standard library module to Python 3.2
|
||||||
License: Python
|
License: Python
|
||||||
URL: https://github.com/agronholm/pythonfutures
|
URL: https://github.com/agronholm/pythonfutures
|
||||||
Source0: https://files.pythonhosted.org/packages/source/f/futures/futures-%{version}.tar.gz
|
Source0: https://files.pythonhosted.org/packages/source/f/futures/futures-%{version}.tar.gz
|
||||||
|
Patch01: 0001-Backport-thread_name_prefix-from-upstream-64.patch
|
||||||
|
Patch02: 0002-Specify-python_requires-to-prevent-installation-on-P.patch
|
||||||
|
Patch03: 0003-Backport-fixes-to-as_completed-and-map-iterators-bpo.patch
|
||||||
|
Patch04: 0004-Make-Future.__repr__-subclass-friendly-bpo-22033-65.patch
|
||||||
|
Patch05: 0005-Fixed-tests-hanging-on-PyPy.patch
|
||||||
BuildRequires: python2-devel
|
BuildRequires: python2-devel
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
|
|
||||||
@ -39,5 +44,20 @@ The concurrent.futures module provides a high-level interface for asynchronously
|
|||||||
%{python2_sitelib}/futures-*.egg-info*
|
%{python2_sitelib}/futures-*.egg-info*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Dec 29 2023 zhangliangpengkun<zhangliangpengkun@xfusion.com> - 3.1.1-10
|
||||||
|
- Fixed tests hanging on PyPy
|
||||||
|
|
||||||
|
* Wed Dec 27 2023 zhangliangpengkun<zhangliangpengkun@xfusion.com> - 3.1.1-9
|
||||||
|
- Make Future.__repr__ subclass-friendly (bpo-22033) (#65)
|
||||||
|
|
||||||
|
* Thu Dec 21 2023 zhangliangpengkun<zhangliangpengkun@xfusion.com> - 3.1.1-8
|
||||||
|
- Backport fixes to as_completed and map iterators (bpo-27144) (#66)
|
||||||
|
|
||||||
|
* Thu Nov 02 2023 zhangliangpengkun<zhangliangpengkun@xfusion.com> - 3.1.1-7
|
||||||
|
- Specify python_requires to prevent installation on Python 3
|
||||||
|
|
||||||
|
* Fri Oct 13 2023 zhangliangpengkun<zhangliangpengkun@xfusion.com> - 3.1.1-6
|
||||||
|
- fix Backport `thread_name_prefix` from upstream (#64)
|
||||||
|
|
||||||
* Mon Oct 14 2019 Lijin Yang <yanglijin@huawei.com> - 3.1.1-5
|
* Mon Oct 14 2019 Lijin Yang <yanglijin@huawei.com> - 3.1.1-5
|
||||||
- Package init
|
- Package init
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user