diff options
author | Nick R. Papior <nickpapior@gmail.com> | 2020-09-17 12:29:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-17 12:29:38 +0200 |
commit | 233c63a56974de22b846ac989cef1fabe45e7296 (patch) | |
tree | 1ec1cd1f4b606603fbf3035422070eb581857e7e /numpy/distutils/system_info.py | |
parent | 60a1e10c4593736b188b38e7d7c51aefb213af6a (diff) | |
download | numpy-233c63a56974de22b846ac989cef1fabe45e7296.tar.gz |
BLD: enabled negation of library choices in NPY_*_ORDER (#17219)
BLD: enabled negation of library choices in NPY_*_ORDER
When users build for a particular order it may be beneficial
to disallow certain libraries.
In particular a user may not care about which accelerated
BLAS library is used, so long as the NetLIB or ATLAS library isn't used.
This is now possible with:
NPY_BLAS_ORDER='^blas,atlas'
or
NPY_BLAS_ORDER='!blas,atlas'
Since we may envision more BLAS/LAPACK libraries to the pool, this
will provide greater flexibility as they enter.
A new (local) method is added in system_info.py which removes duplicate
code and allows for easier usage across libraries.
Diffstat (limited to 'numpy/distutils/system_info.py')
-rw-r--r-- | numpy/distutils/system_info.py | 119 |
1 files changed, 85 insertions, 34 deletions
diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index 19f7482f2..b4513825d 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -415,6 +415,83 @@ def get_standard_file(fname): return filenames +def _parse_env_order(base_order, env): + """ Parse an environment variable `env` by splitting with "," and only returning elements from `base_order` + + This method will sequence the environment variable and check for their invidual elements in `base_order`. + + The items in the environment variable may be negated via '^item' or '!itema,itemb'. + It must start with ^/! to negate all options. + + Raises + ------ + ValueError: for mixed negated and non-negated orders or multiple negated orders + + Parameters + ---------- + base_order : list of str + the base list of orders + env : str + the environment variable to be parsed, if none is found, `base_order` is returned + + Returns + ------- + allow_order : list of str + allowed orders in lower-case + unknown_order : list of str + for values not overlapping with `base_order` + """ + order_str = os.environ.get(env, None) + + # ensure all base-orders are lower-case (for easier comparison) + base_order = [order.lower() for order in base_order] + if order_str is None: + return base_order, [] + + neg = order_str.startswith('^') or order_str.startswith('!') + # Check format + order_str_l = list(order_str) + sum_neg = order_str_l.count('^') + order_str_l.count('!') + if neg: + if sum_neg > 1: + raise ValueError(f"Environment variable '{env}' may only contain a single (prefixed) negation: {order_str}") + # remove prefix + order_str = order_str[1:] + elif sum_neg > 0: + raise ValueError(f"Environment variable '{env}' may not mix negated an non-negated items: {order_str}") + + # Split and lower case + orders = order_str.lower().split(',') + + # to inform callee about non-overlapping elements + unknown_order = [] + + # if negated, we have to remove from the order + if neg: + allow_order = base_order.copy() + + for order in orders: + if order not in base_order: + unknown_order.append(order) + continue + + if order in allow_order: + allow_order.remove(order) + + else: + allow_order = [] + + for order in orders: + if order not in base_order: + unknown_order.append(order) + continue + + if order not in allow_order: + allow_order.append(order) + + return allow_order, unknown_order + + def get_info(name, notfound_action=0): """ notfound_action: @@ -1766,24 +1843,11 @@ class lapack_opt_info(system_info): return getattr(self, '_calc_info_{}'.format(name))() def calc_info(self): - user_order = os.environ.get(self.order_env_var_name, None) - if user_order is None: - lapack_order = self.lapack_order - else: - # the user has requested the order of the - # check they are all in the available list, a COMMA SEPARATED list - user_order = user_order.lower().split(',') - non_existing = [] - lapack_order = [] - for order in user_order: - if order in self.lapack_order: - lapack_order.append(order) - elif len(order) > 0: - non_existing.append(order) - if len(non_existing) > 0: - raise ValueError("lapack_opt_info user defined " - "LAPACK order has unacceptable " - "values: {}".format(non_existing)) + lapack_order, unknown_order = _parse_env_order(self.lapack_order, self.order_env_var_name) + if len(unknown_order) > 0: + raise ValueError("lapack_opt_info user defined " + "LAPACK order has unacceptable " + "values: {}".format(unknown_order)) for lapack in lapack_order: if self._calc_info(lapack): @@ -1911,22 +1975,9 @@ class blas_opt_info(system_info): return getattr(self, '_calc_info_{}'.format(name))() def calc_info(self): - user_order = os.environ.get(self.order_env_var_name, None) - if user_order is None: - blas_order = self.blas_order - else: - # the user has requested the order of the - # check they are all in the available list - user_order = user_order.lower().split(',') - non_existing = [] - blas_order = [] - for order in user_order: - if order in self.blas_order: - blas_order.append(order) - elif len(order) > 0: - non_existing.append(order) - if len(non_existing) > 0: - raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(non_existing)) + blas_order, unknown_order = _parse_env_order(self.blas_order, self.order_env_var_name) + if len(unknown_order) > 0: + raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(unknown_order)) for blas in blas_order: if self._calc_info(blas): |