commit 697ea796dc90fdc8ed3fa2ca25ed80add196d987 Author: tigro Date: Sat Jan 4 11:51:29 2025 +0300 import python-numexpr-2.8.5-7.el10 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a6c40f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/numexpr-2.8.5.tar.gz diff --git a/.python-numexpr.metadata b/.python-numexpr.metadata new file mode 100644 index 0000000..93a7c97 --- /dev/null +++ b/.python-numexpr.metadata @@ -0,0 +1 @@ +fbd681371c05653c3595149bf25102d5b806b2b6 SOURCES/numexpr-2.8.5.tar.gz diff --git a/SOURCES/0002-Revert-Make-more-difficult-sanitize-of-the-expressio.patch b/SOURCES/0002-Revert-Make-more-difficult-sanitize-of-the-expressio.patch new file mode 100644 index 0000000..122fd6b --- /dev/null +++ b/SOURCES/0002-Revert-Make-more-difficult-sanitize-of-the-expressio.patch @@ -0,0 +1,254 @@ +From be21651a1fada038b8ca00938d063fbb3336b989 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 16 Aug 2023 17:23:26 +0200 +Subject: [PATCH 2/7] Revert "Make more difficult sanitize of the expression + string before eval" + +This reverts commit 00b035c78ca5ac209b58b56b5dcc99596cac423c. +--- + ANNOUNCE.rst | 23 ++--------------------- + RELEASE_NOTES.rst | 19 +------------------ + doc/user_guide.rst | 27 ++++++++++----------------- + numexpr/necompiler.py | 27 ++++++++------------------- + numexpr/tests/test_numexpr.py | 18 ++---------------- + 5 files changed, 23 insertions(+), 91 deletions(-) + +diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst +index 4e9070f2cc..f038df4f44 100644 +--- a/ANNOUNCE.rst ++++ b/ANNOUNCE.rst +@@ -4,10 +4,7 @@ Announcing NumExpr 2.8.5 + + Hi everyone, + +-In 2.8.5 we have added a new function, `validate` which checks an expression `ex` +-for validity, for usage where the program is parsing a user input. There are also +-consequences for this sort of usage, since `eval(ex)` is called, and as such we +-do some string sanitization as described below. ++**Under development.** + + Project documentation is available at: + +@@ -16,23 +13,7 @@ http://numexpr.readthedocs.io/ + Changes from 2.8.4 to 2.8.5 + --------------------------- + +-* A `validate` function has been added. This function checks the inputs, returning +- `None` on success or raising an exception on invalid inputs. This function was +- added as numerous projects seem to be using NumExpr for parsing user inputs. +- `re_evaluate` may be called directly following `validate`. +-* As an addendum to the use of NumExpr for parsing user inputs, is that NumExpr +- calls `eval` on the inputs. A regular expression is now applied to help sanitize +- the input expression string, forbidding '__', ':', and ';'. Attribute access +- is also banned except for '.r' for real and '.i' for imag. +-* Thanks to timbrist for a fix to behavior of NumExpr with integers to negative +- powers. NumExpr was pre-checking integer powers for negative values, which +- was both inefficient and causing parsing errors in some situations. Now NumExpr +- will simply return 0 as a result for such cases. While NumExpr generally tries +- to follow NumPy behavior, performance is also critical. +-* Thanks to peadar for some fixes to how NumExpr launches threads for embedded +- applications. +-* Thanks to de11n for making parsing of the `site.cfg` for MKL consistent among +- all shared platforms. ++**Under development.** + + + What's Numexpr? +diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst +index 9cf5d3977b..4929a42e12 100644 +--- a/RELEASE_NOTES.rst ++++ b/RELEASE_NOTES.rst +@@ -5,24 +5,7 @@ Release notes for NumExpr 2.8 series + Changes from 2.8.4 to 2.8.5 + --------------------------- + +-* A `validate` function has been added. This function checks the inputs, returning +- `None` on success or raising an exception on invalid inputs. This function was +- added as numerous projects seem to be using NumExpr for parsing user inputs. +- `re_evaluate` may be called directly following `validate`. +-* As an addendum to the use of NumExpr for parsing user inputs, is that NumExpr +- calls `eval` on the inputs. A regular expression is now applied to help sanitize +- the input expression string, forbidding '__', ':', and ';'. Attribute access +- is also banned except for '.r' for real and '.i' for imag. +-* Thanks to timbrist for a fix to behavior of NumExpr with integers to negative +- powers. NumExpr was pre-checking integer powers for negative values, which +- was both inefficient and causing parsing errors in some situations. Now NumExpr +- will simply return 0 as a result for such cases. While NumExpr generally tries +- to follow NumPy behavior, performance is also critical. +-* Thanks to peadar for some fixes to how NumExpr launches threads for embedded +- applications. +-* Thanks to de11n for making parsing of the `site.cfg` for MKL consistent among +- all shared platforms. +- ++**Under development.** + + Changes from 2.8.3 to 2.8.4 + --------------------------- +diff --git a/doc/user_guide.rst b/doc/user_guide.rst +index 3a3cf63d9c..74306eb658 100644 +--- a/doc/user_guide.rst ++++ b/doc/user_guide.rst +@@ -1,7 +1,7 @@ +-NumExpr 2.8 User Guide ++NumExpr 2.0 User Guide + ====================== + +-The NumExpr package supplies routines for the fast evaluation of ++The :code:`numexpr` package supplies routines for the fast evaluation of + array expressions elementwise by using a vector-based virtual + machine. + +@@ -11,33 +11,23 @@ Using it is simple:: + >>> import numexpr as ne + >>> a = np.arange(10) + >>> b = np.arange(0, 20, 2) +- >>> c = ne.evaluate('2*a + 3*b') ++ >>> c = ne.evaluate("2*a+3*b") + >>> c + array([ 0, 8, 16, 24, 32, 40, 48, 56, 64, 72]) + + +-It is also possible to use NumExpr to validate an expression:: +- +- >>> ne.validate('2*a + 3*b') +- +-which returns `None` on success or raises an exception on invalid inputs. +- +-and it can also re_evaluate an expression:: +- +- >>> b = np.arange(0, 40, 4) +- >>> ne.re_evaluate() +- + Building + -------- + +-*NumExpr* requires Python_ 3.7 or greater, and NumPy_ 1.13 or greater. It is ++*NumExpr* requires Python_ 2.6 or greater, and NumPy_ 1.7 or greater. It is + built in the standard Python way: + + .. code-block:: bash + +- $ pip install . ++ $ python setup.py build ++ $ python setup.py install + +-You must have a C-compiler (i.e. MSVC Build tools on Windows and GCC on Linux) installed. ++You must have a C-compiler (i.e. MSVC on Windows and GCC on Linux) installed. + + Then change to a directory that is not the repository directory (e.g. `/tmp`) and + test :code:`numexpr` with: +@@ -278,6 +268,9 @@ General routines + * :code:`detect_number_of_cores()`: Detects the number of cores on a system. + + ++ ++ ++ + Intel's VML specific support routines + ------------------------------------- + +diff --git a/numexpr/necompiler.py b/numexpr/necompiler.py +index cbf290932b..fef886baf5 100644 +--- a/numexpr/necompiler.py ++++ b/numexpr/necompiler.py +@@ -260,17 +260,15 @@ class Immediate(Register): + def __str__(self): + return 'Immediate(%d)' % (self.node.value,) + +- +-_forbidden_re = re.compile('[\;[\:]|__|\.[abcdefghjklmnopqstuvwxyzA-Z_]') ++_forbidden_re = re.compile('[\;[\:]|__') + def stringToExpression(s, types, context): + """Given a string, convert it to a tree of ExpressionNode's. + """ + # sanitize the string for obvious attack vectors that NumExpr cannot + # parse into its homebrew AST. This is to protect the call to `eval` below. +- # We forbid `;`, `:`. `[` and `__`, and attribute access via '.'. +- # We cannot ban `.real` or `.imag` however... +- no_whitespace = re.sub(r'\s+', '', s) +- if _forbidden_re.search(no_whitespace) is not None: ++ # We forbid `;`, `:`. `[` and `__` ++ # We would like to forbid `.` but it is both a reference and decimal point. ++ if _forbidden_re.search(s) is not None: + raise ValueError(f'Expression {s} has forbidden control characters.') + + old_ctx = expressions._context.get_current_context() +@@ -768,6 +766,7 @@ def getArguments(names, local_dict=None, global_dict=None, _frame_depth: int=2): + _names_cache = CacheDict(256) + _numexpr_cache = CacheDict(256) + _numexpr_last = {} ++_numexpr_sanity = set() + evaluate_lock = threading.Lock() + + # MAYBE: decorate this function to add attributes instead of having the +@@ -829,13 +828,6 @@ def validate(ex: str, + _frame_depth: int + The calling frame depth. Unless you are a NumExpr developer you should + not set this value. +- +- Note +- ---- +- Both `validate` and by extension `evaluate` call `eval(ex)`, which is +- potentially dangerous on unsanitized inputs. As such, NumExpr does some +- sanitization, banning the character ':;[', the dunder '__', and attribute +- access to all but '.r' for real and '.i' for imag access to complex numbers. + """ + global _numexpr_last + +@@ -865,6 +857,8 @@ def validate(ex: str, + kwargs = {'out': out, 'order': order, 'casting': casting, + 'ex_uses_vml': ex_uses_vml} + _numexpr_last = dict(ex=compiled_ex, argnames=names, kwargs=kwargs) ++ # with evaluate_lock: ++ # return compiled_ex(*arguments, **kwargs) + except Exception as e: + return e + return None +@@ -924,12 +918,7 @@ def evaluate(ex: str, + The calling frame depth. Unless you are a NumExpr developer you should + not set this value. + +- Note +- ---- +- Both `validate` and by extension `evaluate` call `eval(ex)`, which is +- potentially dangerous on unsanitized inputs. As such, NumExpr does some +- sanitization, banning the character ':;[', the dunder '__', and attribute +- access to all but '.r' for real and '.i' for imag access to complex numbers. ++ + """ + # We could avoid code duplication if we called validate and then re_evaluate + # here, but they we have difficulties with the `sys.getframe(2)` call in +diff --git a/numexpr/tests/test_numexpr.py b/numexpr/tests/test_numexpr.py +index a9f917fccd..ebc41c8d54 100644 +--- a/numexpr/tests/test_numexpr.py ++++ b/numexpr/tests/test_numexpr.py +@@ -536,27 +536,13 @@ class test_evaluate(TestCase): + + # Forbid semicolon + try: +- evaluate('import os;') ++ evaluate('import os; os.cpu_count()') + except ValueError: + pass + else: + self.fail() + +- # Attribute access +- try: +- evaluate('os.cpucount()') +- except ValueError: +- pass +- else: +- self.fail() +- +- # But decimal point must pass +- a = 3.0 +- evaluate('a*2.') +- evaluate('2.+a') +- +- +- ++ # I struggle to come up with cases for our ban on `'` and `"` + + + diff --git a/SOURCES/0003-Revert-Add-in-protections-against-call-to-eval-expre.patch b/SOURCES/0003-Revert-Add-in-protections-against-call-to-eval-expre.patch new file mode 100644 index 0000000..18be71a --- /dev/null +++ b/SOURCES/0003-Revert-Add-in-protections-against-call-to-eval-expre.patch @@ -0,0 +1,183 @@ +From aa18c52226ddf3d5a3448702fc2b1a14b0ee3c2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 16 Aug 2023 17:23:36 +0200 +Subject: [PATCH 3/7] Revert "Add in protections against call to + `eval(expression)`" + +This reverts commit 4b2d89cf14e75030d27629925b9998e1e91d23c7. +--- + numexpr/necompiler.py | 26 +++++++----------- + numexpr/tests/test_numexpr.py | 50 ++++------------------------------- + 2 files changed, 15 insertions(+), 61 deletions(-) + +diff --git a/numexpr/necompiler.py b/numexpr/necompiler.py +index fef886baf5..37052acadb 100644 +--- a/numexpr/necompiler.py ++++ b/numexpr/necompiler.py +@@ -13,7 +13,6 @@ import __future__ + import sys + import numpy + import threading +-import re + + is_cpu_amd_intel = False # DEPRECATION WARNING: WILL BE REMOVED IN FUTURE RELEASE + from numexpr import interpreter, expressions, use_vml +@@ -260,17 +259,10 @@ class Immediate(Register): + def __str__(self): + return 'Immediate(%d)' % (self.node.value,) + +-_forbidden_re = re.compile('[\;[\:]|__') ++ + def stringToExpression(s, types, context): + """Given a string, convert it to a tree of ExpressionNode's. + """ +- # sanitize the string for obvious attack vectors that NumExpr cannot +- # parse into its homebrew AST. This is to protect the call to `eval` below. +- # We forbid `;`, `:`. `[` and `__` +- # We would like to forbid `.` but it is both a reference and decimal point. +- if _forbidden_re.search(s) is not None: +- raise ValueError(f'Expression {s} has forbidden control characters.') +- + old_ctx = expressions._context.get_current_context() + try: + expressions._context.set_new_context(context) +@@ -293,10 +285,8 @@ def stringToExpression(s, types, context): + t = types.get(name, default_type) + names[name] = expressions.VariableNode(name, type_to_kind[t]) + names.update(expressions.functions) +- + # now build the expression + ex = eval(c, names) +- + if expressions.isConstant(ex): + ex = expressions.ConstantNode(ex, expressions.getKind(ex)) + elif not isinstance(ex, expressions.ExpressionNode): +@@ -621,7 +611,9 @@ def NumExpr(ex, signature=(), **kwargs): + + Returns a `NumExpr` object containing the compiled function. + """ +- ++ # NumExpr can be called either directly by the end-user, in which case ++ # kwargs need to be sanitized by getContext, or by evaluate, ++ # in which case kwargs are in already sanitized. + # In that case _frame_depth is wrong (it should be 2) but it doesn't matter + # since it will not be used (because truediv='auto' has already been + # translated to either True or False). +@@ -766,7 +758,7 @@ def getArguments(names, local_dict=None, global_dict=None, _frame_depth: int=2): + _names_cache = CacheDict(256) + _numexpr_cache = CacheDict(256) + _numexpr_last = {} +-_numexpr_sanity = set() ++ + evaluate_lock = threading.Lock() + + # MAYBE: decorate this function to add attributes instead of having the +@@ -869,7 +861,7 @@ def evaluate(ex: str, + out: numpy.ndarray = None, + order: str = 'K', + casting: str = 'safe', +- _frame_depth: int = 3, ++ _frame_depth: int=3, + **kwargs) -> numpy.ndarray: + """ + Evaluate a simple array expression element-wise using the virtual machine. +@@ -917,8 +909,6 @@ def evaluate(ex: str, + _frame_depth: int + The calling frame depth. Unless you are a NumExpr developer you should + not set this value. +- +- + """ + # We could avoid code duplication if we called validate and then re_evaluate + # here, but they we have difficulties with the `sys.getframe(2)` call in +@@ -931,6 +921,10 @@ def evaluate(ex: str, + else: + raise e + ++ ++ ++ ++ + def re_evaluate(local_dict: Optional[Dict] = None, + _frame_depth: int=2) -> numpy.ndarray: + """ +diff --git a/numexpr/tests/test_numexpr.py b/numexpr/tests/test_numexpr.py +index ebc41c8d54..ccb0b6cb07 100644 +--- a/numexpr/tests/test_numexpr.py ++++ b/numexpr/tests/test_numexpr.py +@@ -373,9 +373,8 @@ class test_evaluate(TestCase): + a1 = array([1., 2., 3.]) + b1 = array([4., 5., 6.]) + c1 = array([7., 8., 9.]) +- local_dict={'a': a1, 'b': b1, 'c': c1} +- x = evaluate("2*a + 3*b*c", local_dict=local_dict) +- x = re_evaluate(local_dict=local_dict) ++ x = evaluate("2*a + 3*b*c", local_dict={'a': a1, 'b': b1, 'c': c1}) ++ x = re_evaluate() + assert_array_equal(x, array([86., 124., 168.])) + + def test_validate(self): +@@ -401,10 +400,9 @@ class test_evaluate(TestCase): + a1 = array([1., 2., 3.]) + b1 = array([4., 5., 6.]) + c1 = array([7., 8., 9.]) +- local_dict={'a': a1, 'b': b1, 'c': c1} +- retval = validate("2*a + 3*b*c", local_dict=local_dict) ++ retval = validate("2*a + 3*b*c", local_dict={'a': a1, 'b': b1, 'c': c1}) + assert(retval is None) +- x = re_evaluate(local_dict=local_dict) ++ x = re_evaluate() + assert_array_equal(x, array([86., 124., 168.])) + + # Test for issue #22 +@@ -504,49 +502,11 @@ class test_evaluate(TestCase): + a = arange(3) + try: + evaluate("a < [0, 0, 0]") +- except (ValueError, TypeError): ++ except TypeError: + pass + else: + self.fail() + +- def test_forbidden_tokens(self): +- # Forbid dunder +- try: +- evaluate('__builtins__') +- except ValueError: +- pass +- else: +- self.fail() +- +- # Forbid colon for lambda funcs +- try: +- evaluate('lambda x: x') +- except ValueError: +- pass +- else: +- self.fail() +- +- # Forbid indexing +- try: +- evaluate('locals()[]') +- except ValueError: +- pass +- else: +- self.fail() +- +- # Forbid semicolon +- try: +- evaluate('import os; os.cpu_count()') +- except ValueError: +- pass +- else: +- self.fail() +- +- # I struggle to come up with cases for our ban on `'` and `"` +- +- +- +- + def test_disassemble(self): + assert_equal(disassemble(NumExpr( + "where(m, a, -1)", [('m', bool), ('a', float)])), diff --git a/SOURCES/0004-Revert-Adding-tests-for-validate-and-noticed-that-re.patch b/SOURCES/0004-Revert-Adding-tests-for-validate-and-noticed-that-re.patch new file mode 100644 index 0000000..9430088 --- /dev/null +++ b/SOURCES/0004-Revert-Adding-tests-for-validate-and-noticed-that-re.patch @@ -0,0 +1,80 @@ +From d3f418e5f469be66f8e974e5b53487bd8698dea4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 16 Aug 2023 17:23:41 +0200 +Subject: [PATCH 4/7] Revert "Adding tests for `validate` and noticed that + `re_evaluate` tests using `local_dict` argument are flawed and do not + actually work" + +This reverts commit 74d597398ba3c379c196e469d40f516de110eaa5. +--- + numexpr/__init__.py | 3 +-- + numexpr/tests/test_numexpr.py | 32 ++------------------------------ + 2 files changed, 3 insertions(+), 32 deletions(-) + +diff --git a/numexpr/__init__.py b/numexpr/__init__.py +index 7946f8522d..9cabe69589 100644 +--- a/numexpr/__init__.py ++++ b/numexpr/__init__.py +@@ -31,8 +31,7 @@ is_cpu_amd_intel = False # DEPRECATION WARNING: WILL BE REMOVED IN FUTURE RELEAS + import os, os.path + import platform + from numexpr.expressions import E +-from numexpr.necompiler import (NumExpr, disassemble, evaluate, re_evaluate, +- validate) ++from numexpr.necompiler import NumExpr, disassemble, evaluate, re_evaluate + + from numexpr.utils import (_init_num_threads, + get_vml_version, set_vml_accuracy_mode, set_vml_num_threads, +diff --git a/numexpr/tests/test_numexpr.py b/numexpr/tests/test_numexpr.py +index ccb0b6cb07..32f5be4b75 100644 +--- a/numexpr/tests/test_numexpr.py ++++ b/numexpr/tests/test_numexpr.py +@@ -31,7 +31,7 @@ from numpy.testing import (assert_equal, assert_array_equal, + from numpy import shape, allclose, array_equal, ravel, isnan, isinf + + import numexpr +-from numexpr import E, NumExpr, evaluate, re_evaluate, validate, disassemble, use_vml ++from numexpr import E, NumExpr, evaluate, re_evaluate, disassemble, use_vml + from numexpr.expressions import ConstantNode + + import unittest +@@ -370,38 +370,10 @@ class test_evaluate(TestCase): + assert_array_equal(x, array([86., 124., 168.])) + + def test_re_evaluate_dict(self): +- a1 = array([1., 2., 3.]) +- b1 = array([4., 5., 6.]) +- c1 = array([7., 8., 9.]) +- x = evaluate("2*a + 3*b*c", local_dict={'a': a1, 'b': b1, 'c': c1}) +- x = re_evaluate() +- assert_array_equal(x, array([86., 124., 168.])) +- +- def test_validate(self): + a = array([1., 2., 3.]) + b = array([4., 5., 6.]) + c = array([7., 8., 9.]) +- retval = validate("2*a + 3*b*c") +- assert(retval is None) +- x = re_evaluate() +- assert_array_equal(x, array([86., 124., 168.])) +- +- def test_validate_missing_var(self): +- a = array([1., 2., 3.]) +- b = array([4., 5., 6.]) +- retval = validate("2*a + 3*b*c") +- assert(isinstance(retval, KeyError)) +- +- def test_validate_syntax(self): +- retval = validate("2+") +- assert(isinstance(retval, SyntaxError)) +- +- def test_validate_dict(self): +- a1 = array([1., 2., 3.]) +- b1 = array([4., 5., 6.]) +- c1 = array([7., 8., 9.]) +- retval = validate("2*a + 3*b*c", local_dict={'a': a1, 'b': b1, 'c': c1}) +- assert(retval is None) ++ x = evaluate("2*a + 3*b*c", local_dict={'a': a, 'b': b, 'c': c}) + x = re_evaluate() + assert_array_equal(x, array([86., 124., 168.])) + diff --git a/SOURCES/0005-Revert-Add-in-docstring-intro-for-validate.patch b/SOURCES/0005-Revert-Add-in-docstring-intro-for-validate.patch new file mode 100644 index 0000000..eff661b --- /dev/null +++ b/SOURCES/0005-Revert-Add-in-docstring-intro-for-validate.patch @@ -0,0 +1,26 @@ +From 5bdab6e1f4d896c251270fdbe6efe77120670500 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 16 Aug 2023 17:24:33 +0200 +Subject: [PATCH 5/7] Revert "Add in docstring intro for `validate(...)`" + +This reverts commit da39566c2c379888991e4eb1dae95d917e13db8a. +--- + numexpr/necompiler.py | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/numexpr/necompiler.py b/numexpr/necompiler.py +index 37052acadb..f846c1d23d 100644 +--- a/numexpr/necompiler.py ++++ b/numexpr/necompiler.py +@@ -772,10 +772,7 @@ def validate(ex: str, + _frame_depth: int = 2, + **kwargs) -> Optional[Exception]: + """ +- Validate a NumExpr expression with the given `local_dict` or `locals()`. +- Returns `None` on success and the Exception object if one occurs. Note that +- you can proceed directly to call `re_evaluate()` if you use `validate()` +- to sanitize your expressions and variables in advance. ++ Returns + + Parameters + ---------- diff --git a/SOURCES/0006-Revert-Add-a-validate-.-function-that-can-be-used-to.patch b/SOURCES/0006-Revert-Add-a-validate-.-function-that-can-be-used-to.patch new file mode 100644 index 0000000..44039ee --- /dev/null +++ b/SOURCES/0006-Revert-Add-a-validate-.-function-that-can-be-used-to.patch @@ -0,0 +1,307 @@ +From b773b8ba12431b7d15f9812e29861de327d0cd8f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 16 Aug 2023 17:24:36 +0200 +Subject: [PATCH 6/7] Revert "Add a `validate(...)` function that can be used + to sansitize the expression and variables before starting the virtual + machine." + +This reverts commit 21ff376a0853aff6aea63343c6010d6434917319. +--- + numexpr/necompiler.py | 194 +++++++++++------------------------------- + 1 file changed, 51 insertions(+), 143 deletions(-) + +diff --git a/numexpr/necompiler.py b/numexpr/necompiler.py +index f846c1d23d..9291d44244 100644 +--- a/numexpr/necompiler.py ++++ b/numexpr/necompiler.py +@@ -8,7 +8,6 @@ + # rights to use. + #################################################################### + +-from typing import Optional, Dict + import __future__ + import sys + import numpy +@@ -527,7 +526,7 @@ context_info = [ + ] + + +-def getContext(kwargs, _frame_depth=1): ++def getContext(kwargs, frame_depth=1): + d = kwargs.copy() + context = {} + for name, allowed, default in context_info: +@@ -536,11 +535,11 @@ def getContext(kwargs, _frame_depth=1): + context[name] = value + else: + raise ValueError("'%s' must be one of %s" % (name, allowed)) +- ++ + if d: + raise ValueError("Unknown keyword argument '%s'" % d.popitem()[0]) + if context['truediv'] == 'auto': +- caller_globals = sys._getframe(_frame_depth + 1).f_globals ++ caller_globals = sys._getframe(frame_depth + 1).f_globals + context['truediv'] = caller_globals.get('division', None) == __future__.division + + return context +@@ -614,11 +613,11 @@ def NumExpr(ex, signature=(), **kwargs): + # NumExpr can be called either directly by the end-user, in which case + # kwargs need to be sanitized by getContext, or by evaluate, + # in which case kwargs are in already sanitized. +- # In that case _frame_depth is wrong (it should be 2) but it doesn't matter ++ # In that case frame_depth is wrong (it should be 2) but it doesn't matter + # since it will not be used (because truediv='auto' has already been + # translated to either True or False). +- _frame_depth = 1 +- context = getContext(kwargs, _frame_depth=_frame_depth) ++ ++ context = getContext(kwargs, frame_depth=1) + threeAddrProgram, inputsig, tempsig, constants, input_names = precompile(ex, signature, context) + program = compileThreeAddrForm(threeAddrProgram) + return interpreter.NumExpr(inputsig.encode('ascii'), +@@ -718,11 +717,11 @@ def getExprNames(text, context): + return [a.value for a in input_order], ex_uses_vml + + +-def getArguments(names, local_dict=None, global_dict=None, _frame_depth: int=2): ++def getArguments(names, local_dict=None, global_dict=None): + """ + Get the arguments based on the names. + """ +- call_frame = sys._getframe(_frame_depth) ++ call_frame = sys._getframe(2) + + clear_local_dict = False + if local_dict is None: +@@ -761,40 +760,32 @@ _numexpr_last = {} + + evaluate_lock = threading.Lock() + +-# MAYBE: decorate this function to add attributes instead of having the +-# _numexpr_last dictionary? +-def validate(ex: str, +- local_dict: Optional[Dict] = None, +- global_dict: Optional[Dict] = None, +- out: numpy.ndarray = None, +- order: str = 'K', +- casting: str = 'safe', +- _frame_depth: int = 2, +- **kwargs) -> Optional[Exception]: ++def evaluate(ex, local_dict=None, global_dict=None, ++ out=None, order='K', casting='safe', **kwargs): + """ +- Returns ++ Evaluate a simple array expression element-wise, using the new iterator. ++ ++ ex is a string forming an expression, like "2*a+3*b". The values for "a" ++ and "b" will by default be taken from the calling function's frame ++ (through use of sys._getframe()). Alternatively, they can be specifed ++ using the 'local_dict' or 'global_dict' arguments. + + Parameters + ---------- +- ex: str +- a string forming an expression, like "2*a+3*b". The values for "a" +- and "b" will by default be taken from the calling function's frame +- (through use of sys._getframe()). Alternatively, they can be specified +- using the 'local_dict' or 'global_dict' arguments. + +- local_dict: dictionary, optional ++ local_dict : dictionary, optional + A dictionary that replaces the local operands in current frame. + +- global_dict: dictionary, optional ++ global_dict : dictionary, optional + A dictionary that replaces the global operands in current frame. + +- out: NumPy array, optional ++ out : NumPy array, optional + An existing array where the outcome is going to be stored. Care is + required so that this array has the same shape and type than the + actual outcome of the computation. Useful for avoiding unnecessary + new array allocations. + +- order: {'C', 'F', 'A', or 'K'}, optional ++ order : {'C', 'F', 'A', or 'K'}, optional + Controls the iteration order for operands. 'C' means C order, 'F' + means Fortran order, 'A' means 'F' order if all the arrays are + Fortran contiguous, 'C' order otherwise, and 'K' means as close to +@@ -802,7 +793,7 @@ def validate(ex: str, + efficient computations, typically 'K'eep order (the default) is + desired. + +- casting: {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional ++ casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur when making a copy or + buffering. Setting this to 'unsafe' is not recommended, as it can + adversely affect accumulations. +@@ -813,117 +804,37 @@ def validate(ex: str, + * 'same_kind' means only safe casts or casts within a kind, + like float64 to float32, are allowed. + * 'unsafe' means any data conversions may be done. +- +- _frame_depth: int +- The calling frame depth. Unless you are a NumExpr developer you should +- not set this value. + """ + global _numexpr_last +- +- try: +- +- if not isinstance(ex, str): +- raise ValueError("must specify expression as a string") +- +- # Get the names for this expression +- context = getContext(kwargs) +- expr_key = (ex, tuple(sorted(context.items()))) +- if expr_key not in _names_cache: +- _names_cache[expr_key] = getExprNames(ex, context) +- names, ex_uses_vml = _names_cache[expr_key] +- arguments = getArguments(names, local_dict, global_dict, _frame_depth=_frame_depth) +- +- # Create a signature +- signature = [(name, getType(arg)) for (name, arg) in +- zip(names, arguments)] +- +- # Look up numexpr if possible. +- numexpr_key = expr_key + (tuple(signature),) +- try: +- compiled_ex = _numexpr_cache[numexpr_key] +- except KeyError: +- compiled_ex = _numexpr_cache[numexpr_key] = NumExpr(ex, signature, **context) +- kwargs = {'out': out, 'order': order, 'casting': casting, +- 'ex_uses_vml': ex_uses_vml} +- _numexpr_last = dict(ex=compiled_ex, argnames=names, kwargs=kwargs) +- # with evaluate_lock: +- # return compiled_ex(*arguments, **kwargs) +- except Exception as e: +- return e +- return None +- +-def evaluate(ex: str, +- local_dict: Optional[Dict] = None, +- global_dict: Optional[Dict] = None, +- out: numpy.ndarray = None, +- order: str = 'K', +- casting: str = 'safe', +- _frame_depth: int=3, +- **kwargs) -> numpy.ndarray: +- """ +- Evaluate a simple array expression element-wise using the virtual machine. +- +- Parameters +- ---------- +- ex: str +- a string forming an expression, like "2*a+3*b". The values for "a" +- and "b" will by default be taken from the calling function's frame +- (through use of sys._getframe()). Alternatively, they can be specified +- using the 'local_dict' or 'global_dict' arguments. +- +- local_dict: dictionary, optional +- A dictionary that replaces the local operands in current frame. +- +- global_dict: dictionary, optional +- A dictionary that replaces the global operands in current frame. +- +- out: NumPy array, optional +- An existing array where the outcome is going to be stored. Care is +- required so that this array has the same shape and type than the +- actual outcome of the computation. Useful for avoiding unnecessary +- new array allocations. +- +- order: {'C', 'F', 'A', or 'K'}, optional +- Controls the iteration order for operands. 'C' means C order, 'F' +- means Fortran order, 'A' means 'F' order if all the arrays are +- Fortran contiguous, 'C' order otherwise, and 'K' means as close to +- the order the array elements appear in memory as possible. For +- efficient computations, typically 'K'eep order (the default) is +- desired. +- +- casting: {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional +- Controls what kind of data casting may occur when making a copy or +- buffering. Setting this to 'unsafe' is not recommended, as it can +- adversely affect accumulations. +- +- * 'no' means the data types should not be cast at all. +- * 'equiv' means only byte-order changes are allowed. +- * 'safe' means only casts which can preserve values are allowed. +- * 'same_kind' means only safe casts or casts within a kind, +- like float64 to float32, are allowed. +- * 'unsafe' means any data conversions may be done. +- +- _frame_depth: int +- The calling frame depth. Unless you are a NumExpr developer you should +- not set this value. +- """ +- # We could avoid code duplication if we called validate and then re_evaluate +- # here, but they we have difficulties with the `sys.getframe(2)` call in +- # `getArguments` +- e = validate(ex, local_dict=local_dict, global_dict=global_dict, +- out=out, order=order, casting=casting, +- _frame_depth=_frame_depth, **kwargs) +- if e is None: +- return re_evaluate(local_dict=local_dict, _frame_depth=_frame_depth) +- else: +- raise e ++ if not isinstance(ex, str): ++ raise ValueError("must specify expression as a string") + ++ # Get the names for this expression ++ context = getContext(kwargs, frame_depth=1) ++ expr_key = (ex, tuple(sorted(context.items()))) ++ if expr_key not in _names_cache: ++ _names_cache[expr_key] = getExprNames(ex, context) ++ names, ex_uses_vml = _names_cache[expr_key] ++ arguments = getArguments(names, local_dict, global_dict) + +- ++ # Create a signature ++ signature = [(name, getType(arg)) for (name, arg) in ++ zip(names, arguments)] + ++ # Look up numexpr if possible. ++ numexpr_key = expr_key + (tuple(signature),) ++ try: ++ compiled_ex = _numexpr_cache[numexpr_key] ++ except KeyError: ++ compiled_ex = _numexpr_cache[numexpr_key] = NumExpr(ex, signature, **context) ++ kwargs = {'out': out, 'order': order, 'casting': casting, ++ 'ex_uses_vml': ex_uses_vml} ++ _numexpr_last = dict(ex=compiled_ex, argnames=names, kwargs=kwargs) ++ with evaluate_lock: ++ return compiled_ex(*arguments, **kwargs) + +-def re_evaluate(local_dict: Optional[Dict] = None, +- _frame_depth: int=2) -> numpy.ndarray: ++ ++def re_evaluate(local_dict=None): + """ + Re-evaluate the previous executed array expression without any check. + +@@ -933,20 +844,17 @@ def re_evaluate(local_dict: Optional[Dict] = None, + + Parameters + ---------- +- local_dict: dictionary, optional ++ ++ local_dict : dictionary, optional + A dictionary that replaces the local operands in current frame. +- _frame_depth: int +- The calling frame depth. Unless you are a NumExpr developer you should +- not set this value. ++ + """ +- global _numexpr_last +- + try: + compiled_ex = _numexpr_last['ex'] + except KeyError: +- raise RuntimeError("A previous evaluate() execution was not found, please call `validate` or `evaluate` once before `re_evaluate`") ++ raise RuntimeError("not a previous evaluate() execution found") + argnames = _numexpr_last['argnames'] +- args = getArguments(argnames, local_dict, _frame_depth=_frame_depth) ++ args = getArguments(argnames, local_dict) + kwargs = _numexpr_last['kwargs'] + with evaluate_lock: + return compiled_ex(*args, **kwargs) diff --git a/SOURCES/0007-Use-r-to-avoid-warning-about-unknown-escapes.patch b/SOURCES/0007-Use-r-to-avoid-warning-about-unknown-escapes.patch new file mode 100644 index 0000000..9af0e98 --- /dev/null +++ b/SOURCES/0007-Use-r-to-avoid-warning-about-unknown-escapes.patch @@ -0,0 +1,31 @@ +From 89696f397f167958a6dfc8ccb1f0d796fb4307a3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 16 Aug 2023 17:11:28 +0200 +Subject: [PATCH 7/7] Use r"" to avoid warning about unknown escapes + +--- + numexpr/cpuinfo.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/numexpr/cpuinfo.py b/numexpr/cpuinfo.py +index 4f934b7ba2..4a57d3cb03 100755 +--- a/numexpr/cpuinfo.py ++++ b/numexpr/cpuinfo.py +@@ -105,7 +105,7 @@ class CPUInfoBase(object): + + def __get_nbits(self): + abits = platform.architecture()[0] +- nbits = re.compile('(\d+)bit').search(abits).group(1) ++ nbits = re.compile(r'(\d+)bit').search(abits).group(1) + return nbits + + def _is_32bit(self): +@@ -658,7 +658,7 @@ class Win32CPUInfo(CPUInfoBase): + #XXX: Bad style to use so long `try:...except:...`. Fix it! + + prgx = re.compile(r"family\s+(?P\d+)\s+model\s+(?P\d+)" +- "\s+stepping\s+(?P\d+)", re.IGNORECASE) ++ r"\s+stepping\s+(?P\d+)", re.IGNORECASE) + chnd = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, self.pkey) + pnum = 0 + while 1: diff --git a/SOURCES/0008-Fix-necompiler.getArguments-on-Python-3.13.0b1.patch b/SOURCES/0008-Fix-necompiler.getArguments-on-Python-3.13.0b1.patch new file mode 100644 index 0000000..675fbe9 --- /dev/null +++ b/SOURCES/0008-Fix-necompiler.getArguments-on-Python-3.13.0b1.patch @@ -0,0 +1,28 @@ +From fcceab4c0c59bdbcf79ebca844ac3865bb6e795d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Thu, 30 May 2024 17:04:50 +0200 +Subject: [PATCH] Fix necompiler.getArguments() on Python 3.13.0b1 + +The FrameLocalsProxy object (PEP 667) cannot be cleared. + +Fixes https://github.com/pydata/numexpr/issues/488 +--- + numexpr/necompiler.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/numexpr/necompiler.py b/numexpr/necompiler.py +index 5126bd7..1e60b5a 100644 +--- a/numexpr/necompiler.py ++++ b/numexpr/necompiler.py +@@ -767,7 +767,7 @@ def getArguments(names, local_dict=None, global_dict=None, _frame_depth: int=2): + # If we generated local_dict via an explicit reference to f_locals, + # clear the dict to prevent creating extra ref counts in the caller's scope + # See https://github.com/pydata/numexpr/issues/310 +- if clear_local_dict: ++ if clear_local_dict and hasattr(local_dict, 'clear'): + local_dict.clear() + + return arguments +-- +2.45.0 + diff --git a/SPECS/python-numexpr.spec b/SPECS/python-numexpr.spec new file mode 100644 index 0000000..3e1a253 --- /dev/null +++ b/SPECS/python-numexpr.spec @@ -0,0 +1,299 @@ +## START: Set by rpmautospec +## (rpmautospec version 0.6.5) +## RPMAUTOSPEC: autorelease, autochangelog +%define autorelease(e:s:pb:n) %{?-p:0.}%{lua: + release_number = 7; + base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); + print(release_number + base_release_number - 1); +}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} +## END: Set by rpmautospec + +Summary: Fast numerical array expression evaluator for Python and NumPy +Name: python-numexpr +Version: 2.8.5 +Release: %autorelease +URL: https://github.com/pydata/numexpr +License: MIT +Source: https://github.com/pydata/numexpr/archive/v%{version}/numexpr-%{version}.tar.gz +Patch: 0002-Revert-Make-more-difficult-sanitize-of-the-expressio.patch +Patch: 0003-Revert-Add-in-protections-against-call-to-eval-expre.patch +Patch: 0004-Revert-Adding-tests-for-validate-and-noticed-that-re.patch +Patch: 0005-Revert-Add-in-docstring-intro-for-validate.patch +Patch: 0006-Revert-Add-a-validate-.-function-that-can-be-used-to.patch +Patch: 0007-Use-r-to-avoid-warning-about-unknown-escapes.patch +# https://github.com/pydata/numexpr/pull/489 +Patch: 0008-Fix-necompiler.getArguments-on-Python-3.13.0b1.patch + +BuildRequires: gcc-c++ +BuildRequires: python%{python3_pkgversion}-devel +BuildRequires: python%{python3_pkgversion}-numpy +BuildRequires: python%{python3_pkgversion}-setuptools + +%global _description %{expand: +The numexpr package evaluates multiple-operator array expressions many times +faster than NumPy can. It accepts the expression as a string, analyzes it, +rewrites it more efficiently, and compiles it to faster Python code on the +fly. It’s the next best thing to writing the expression in C and compiling it +with a specialized just-in-time (JIT) compiler, i.e. it does not require a +compiler at runtime.} + +%description %_description + +%package -n python%{python3_pkgversion}-numexpr +Summary: %{summary} +Requires: python%{python3_pkgversion}-numpy >= 1.6 +%{?python_provide:%python_provide python%{python3_pkgversion}-numexpr} + +%description -n python%{python3_pkgversion}-numexpr %_description + +%prep +%autosetup -n numexpr-%{version} -p1 + +# Python 3.13+ has removed unittest.makeSuite() +# Reported upstream: https://github.com/pydata/numexpr/issues/486 +sed -i 's/unittest.makeSuite/unittest.defaultTestLoader.loadTestsFromTestCase/g' $(grep -rl makeSuite) + +%build +%py3_build + +%install +%py3_install +chmod 0755 %{buildroot}%{python3_sitearch}/numexpr/cpuinfo.py +sed -i "1s|/usr/bin/env python$|%{python3}|" %{buildroot}%{python3_sitearch}/numexpr/cpuinfo.py + +%check +pushd build/lib.linux* +%py3_test_envvars %python3 -c 'import numexpr, sys; sys.exit(not numexpr.test().wasSuccessful())' +popd + +%files -n python%{python3_pkgversion}-numexpr +%license LICENSE.txt +%doc ANNOUNCE.rst RELEASE_NOTES.rst README.rst +%{python3_sitearch}/numexpr/ +%{python3_sitearch}/numexpr-%{version}-py*.egg-info + +%changelog +* Sat Jan 04 2025 Arkady L. Shane - 2.8.5-7 +- Rebuilt for MSVSphere 10 + +## START: Generated by rpmautospec +* Fri Jul 19 2024 Fedora Release Engineering - 2.8.5-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Sat Jun 08 2024 Python Maint - 2.8.5-6 +- Rebuilt for Python 3.13 + +* Thu May 30 2024 Karolina Surma - 2.8.5-5 +- Fix compatibility with Python 3.13+ + +* Fri Jan 26 2024 Fedora Release Engineering - 2.8.5-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Mon Jan 22 2024 Fedora Release Engineering - 2.8.5-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Wed Aug 16 2023 Zbigniew Jędrzejewski-Szmek - 2.8.5-2 +- Revert changes in 2.8.5 which causes problems in PyTables (#2231686). + Upstream is still working on a fix, and it seems that this functionality + needs more design work. This reverts all the commits related to + validation of expressions. + +* Mon Aug 07 2023 Zbigniew Jędrzejewski-Szmek - 2.8.5-1 +- Update to 2.8.5 + +* Fri Jul 21 2023 Fedora Release Engineering - 2.8.4-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Tue Jun 13 2023 Python Maint - 2.8.4-2 +- Rebuilt for Python 3.12 + +* Sun Jan 22 2023 Orion Poplawski - 2.8.4-1 +- Update to 2.8.4 + +* Fri Jan 20 2023 Fedora Release Engineering - 2.8.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Fri Jul 22 2022 Fedora Release Engineering - 2.8.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + +* Wed Jun 22 2022 Lumir Balhar - 2.8.1-3 +- Fix build with the latest setuptools + +* Mon Jun 13 2022 Python Maint - 2.8.1-2 +- Rebuilt for Python 3.11 + +* Fri Apr 22 2022 Zbigniew Jędrzejewski-Szmek - 2.8.1-1 +- Version 2.8.1 (rhbz#1869949, rhbz#2061435) + +* Fri Jan 21 2022 Fedora Release Engineering - 2.7.1-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Fri Jul 23 2021 Fedora Release Engineering - 2.7.1-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Fri Jun 04 2021 Python Maint - 2.7.1-6 +- Rebuilt for Python 3.10 + +* Wed Jan 27 2021 Fedora Release Engineering - 2.7.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Wed Jul 29 2020 Fedora Release Engineering - 2.7.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Mon May 25 2020 Miro Hrončok - 2.7.1-3 +- Rebuilt for Python 3.9 + +* Thu Jan 30 2020 Fedora Release Engineering - 2.7.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Sun Jan 5 2020 Zbigniew Jędrzejewski-Szmek - 2.7.1-1 +- Update to latest version (#1787863) + +* Thu Oct 03 2019 Miro Hrončok - 2.7.0-3 +- Rebuilt for Python 3.8.0rc1 (#1748018) + +* Sun Aug 18 2019 Zbigniew Jędrzejewski-Szmek - 2.7.0-2 +- Rebuilt for Python 3.8 + +* Sat Aug 17 2019 Zbigniew Jędrzejewski-Szmek - 2.7.0-1 +- Update to latest version (#1614993) +- Various modernization to the spec file. Actually fail %%check if the test + suite fails. + +* Fri Jul 26 2019 Fedora Release Engineering - 2.6.6-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Mon Jul 08 2019 Miro Hrončok - 2.6.6-3 +- Subpackage python2-numexpr has been removed + See https://fedoraproject.org/wiki/Changes/Mass_Python_2_Package_Removal + +* Sat Feb 02 2019 Fedora Release Engineering - 2.6.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Thu Jul 19 2018 Zbigniew Jędrzejewski-Szmek - 2.6.6-1 +- Update to latest version (#1491485) +- Update spec file, use versioned python macros + +* Sat Jul 14 2018 Fedora Release Engineering - 2.6.1-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Tue Jun 19 2018 Miro Hrončok - 2.6.1-10 +- Rebuilt for Python 3.7 + +* Fri Feb 09 2018 Fedora Release Engineering - 2.6.1-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Tue Oct 24 2017 Haïkel Guémar - 2.6.1-8 +- Fix ELF stripping + +* Thu Aug 03 2017 Fedora Release Engineering - 2.6.1-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 2.6.1-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Sat Feb 11 2017 Fedora Release Engineering - 2.6.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Tue Dec 13 2016 Stratakis Charalampos - 2.6.1-4 +- Rebuild for Python 3.6 + +* Sat Jul 30 2016 Petr Viktorin - 2.6.1-3 +- Make shebang of cpuinfo.py refer to specific Python version (#1361799) + +* Tue Jul 19 2016 Fedora Release Engineering - 2.6.1-2 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Tue Jul 19 2016 Thibault North - 2.6.1-1 +- Update to 2.6.1 +- Fix project URL +- Fix cpuinfo permission in py3 package + +* Wed Jun 1 2016 Zbigniew Jędrzejewski-Szmek - 2.6.0-1 +- Update to latest version + +* Tue May 17 2016 Orion Poplawski - 2.5.2-2 +- Update provides filter +- Use %%python3_pkgversion for EPEL7 compatibility + +* Tue Apr 12 2016 Zbigniew Jędrzejewski-Szmek - 2.5.2-1 +- Update to latest version (#1305251) + +* Sat Feb 6 2016 Zbigniew Jędrzejewski-Szmek - 2.5-1 +- Update to latest version + +* Thu Feb 04 2016 Fedora Release Engineering - 2.4.6-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Nov 18 2015 Zbigniew Jędrzejewski-Szmek - 2.4.6-2 +- Create python2 subpackage + +* Sat Nov 14 2015 Zbigniew Jędrzejewski-Szmek - 2.4.6-1 +- Update to latest version + +* Tue Nov 10 2015 Fedora Release Engineering - 2.3-7 +- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5 + +* Thu Jun 18 2015 Fedora Release Engineering - 2.3-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Sat May 02 2015 Kalev Lember - 2.3-5 +- Rebuilt for GCC 5 C++11 ABI change + +* Sun Aug 17 2014 Fedora Release Engineering - 2.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 2.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 28 2014 Kalev Lember - 2.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4 + +* Tue Jan 28 2014 Thibault North -2.3-1 +- Update to new release 2.3 + +* Fri Jan 17 2014 Zbigniew Jędrzejewski-Szmek - 2.2.2-2 +- Move requirements to the proper package (#1054683) + +* Sun Sep 29 2013 Zbigniew Jędrzejewski-Szmek - 2.2.2-1 +- Update to 2.2.2 (#1013130) + +* Mon Sep 09 2013 Zbigniew Jędrzejewski-Szmek - 2.2.1-1 +- Update to 2.2.1 + +* Thu Sep 05 2013 Zbigniew Jędrzejewski-Szmek - 2.2-1 +- Update to 2.2 +- Add python3-numexpr package + +* Sun Aug 04 2013 Fedora Release Engineering - 2.0.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Thu Feb 14 2013 Fedora Release Engineering - 2.0.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Sat Jul 21 2012 Fedora Release Engineering - 2.0.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Sun Jan 8 2012 Thibault North - 2.0.1-1 +- Update to 2.0.1 + +* Sun Nov 27 2011 Thibault North - 2.0-1 +- Update to 2.0 + +* Sun Oct 30 2011 Thibault North - 1.4.2-2 +- Add check section +- Fix permissions and remove useless sections + +* Thu Oct 20 2011 Thibault North - 1.4.2-1 +- Updated to 1.4.2 + +* Fri Apr 29 2011 Thibault North - 1.4.1-3 +- Fix buildroot issue + +* Tue Dec 21 2010 Thibault North - 1.4.1-2 +- Fixes for the review process + +* Fri Nov 05 2010 Thibault North - 1.4.1-1 +- Initial package based on Mandriva's one + +## END: Generated by rpmautospec